diff --git a/.agents/skills/add-dependency/SKILL.md b/.agents/skills/add-dependency/SKILL.md new file mode 100644 index 000000000..9f4d64b84 --- /dev/null +++ b/.agents/skills/add-dependency/SKILL.md @@ -0,0 +1,248 @@ +--- +name: add-dependency +description: Add a dependency on another ORC resource to a controller. Use when a resource needs to reference or wait for another resource (e.g., Subnet depends on Network). +disable-model-invocation: true +--- + +# Add Dependency to Controller + +Guide for adding a dependency on another ORC resource. + +**Reference**: See `website/docs/development/controller-implementation.md` for detailed rationale on dependency patterns. + +## When to Use Dependencies + +Use a dependency when your controller needs to: +- Wait for another resource to be available before creating +- Reference another resource's OpenStack ID +- Optionally prevent deletion of a resource that's still in use (deletion guard) + +## Key Principles + +See also "Dependency Timing" in [patterns.md](../new-controller/patterns.md) + +### 1. Resolve Dependencies Late + +Resolve dependencies as late as possible, as close to the point of use as possible. This reduces coupling and gives users flexibility when fixing failed deployments. + +**Examples:** +- Subnet depends on Network for creation, but NOT for import by ID or after `status.ID` is set +- Don't require recreating a deleted Network just to delete a Subnet +- Add finalizers only immediately before the OpenStack create/update call + +### 2. Choose the Right Dependency Type + +| Type | Use When | Example | +|------|----------|---------| +| **Normal** (`NewDependency`) | Dependency is optional OR deletion is allowed by OpenStack | Import filter refs, Flavor ref | +| **Deletion Guard** (`NewDeletionGuardDependency`) | Deletion would fail or corrupt your resource | Subnet→Network, Port→Subnet | + +### 3. Use Descriptive Names + +When multiple dependencies of the same type exist, use descriptive prefixes: +- `vipSubnetDependency` not `subnetDependency` (when there could be other subnet refs) +- `sourcePortDependency` vs `destinationPortDependency` +- `memberNetworkDependency` vs `externalNetworkDependency` + +## Dependency Types + +### Normal Dependency +Wait for resource but don't prevent deletion: +```go +dependency.NewDependency[*orcv1alpha1.MyResourceList, *orcv1alpha1.DepResource](...) +``` + +### Deletion Guard Dependency +Wait for resource AND prevent its deletion: +```go +dependency.NewDeletionGuardDependency[*orcv1alpha1.MyResourceList, *orcv1alpha1.DepResource](...) +``` + +**Use Deletion Guard when**: Deleting the dependency would cause your resource to fail or become invalid (e.g., Subnet depends on Network, Port depends on SecurityGroup). + +## Step 1: Add Reference Field to API + +In `api/v1alpha1/_types.go`, add the reference field: + +```go +type MyResourceSpec struct { + // ... + + // projectRef is a reference to a Project. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="projectRef is immutable" + // +optional + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` +} +``` + +For import filters, add to the Filter struct as well: +```go +type MyResourceFilter struct { + // +optional + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` +} +``` + +## Step 2: Declare Dependency + +In `internal/controllers//controller.go`, add package-scoped variable: + +```go +var ( + projectDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.MyResourceList, *orcv1alpha1.Project]( + "spec.resource.projectRef", // Field path for indexing + func(obj *orcv1alpha1.MyResource) []string { + resource := obj.Spec.Resource + if resource == nil || resource.ProjectRef == nil { + return nil + } + return []string{string(*resource.ProjectRef)} + }, + finalizer, externalObjectFieldOwner, + ) + + // For import filter dependencies (no deletion guard needed) + projectImportDependency = dependency.NewDependency[*orcv1alpha1.MyResourceList, *orcv1alpha1.Project]( + "spec.import.filter.projectRef", + func(obj *orcv1alpha1.MyResource) []string { + imp := obj.Spec.Import + if imp == nil || imp.Filter == nil || imp.Filter.ProjectRef == nil { + return nil + } + return []string{string(*imp.Filter.ProjectRef)} + }, + ) +) +``` + +## Step 3: Setup Watches + +In `SetupWithManager()` in `controller.go`: + +```go +func (c myReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + // Create watch handlers + projectWatchHandler, err := projectDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&orcv1alpha1.MyResource{}). + // Watch the dependency + Watches(&orcv1alpha1.Project{}, projectWatchHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ) + + // Register dependencies with manager + if err := errors.Join( + projectDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, k8sClient, builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, helperFactory{}, statusWriter{}) + return builder.Complete(&r) +} +``` + +## Step 4: Use Dependency in Actuator + +In `actuator.go`, resolve the dependency before using it: + +Use `orcv1alpha1.IsAvailable` as the readiness predicate. This is sufficient because `Status.ID` is always set before a resource becomes Available: + +```go +func (actuator myActuator) CreateResource(ctx context.Context, obj *orcv1alpha1.MyResource) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + var projectID string + if resource.ProjectRef != nil { + project, reconcileStatus := projectDependency.GetDependency( + ctx, actuator.k8sClient, obj, + orcv1alpha1.IsAvailable, + ) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + projectID = ptr.Deref(project.Status.ID, "") + } + + createOpts := myresource.CreateOpts{ + ProjectID: projectID, + // ... + } + // ... +} +``` + +For import filter dependencies: +```go +func (actuator myActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + listOpts := myresource.ListOpts{ + ProjectID: ptr.Deref(project.Status.ID, ""), + } + return actuator.osClient.ListMyResources(ctx, listOpts), nil +} +``` + +## Step 5: Add k8sClient to Actuator + +If not already present, add `k8sClient` to the actuator struct: + +```go +type myActuator struct { + osClient osclients.MyResourceClient + k8sClient client.Client // Add this +} +``` + +Update `newActuator()`: +```go +func newActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (myActuator, progress.ReconcileStatus) { + k8sClient := controller.GetK8sClient() // Add this + // ... + return myActuator{ + osClient: osClient, + k8sClient: k8sClient, // Add this + }, nil +} +``` + +## Step 6: Add Tests + +Create dependency tests in `internal/controllers//tests/-dependency/`: +- Test that resource waits for dependency +- Test that dependency deletion is blocked (if using DeletionGuard) + +Follow [testing](../testing/SKILL.md) for running unit tests, linting, and E2E tests. + +## Checklist + +- [ ] Reference field added to API types (with immutability validation) +- [ ] Dependency declared in controller.go +- [ ] Watch configured in SetupWithManager +- [ ] Dependency registered with manager (AddToManager) +- [ ] Dependency resolved in actuator before use +- [ ] k8sClient added to actuator struct +- [ ] `make generate` runs cleanly +- [ ] `make lint` passes +- [ ] Dependency tests added diff --git a/.agents/skills/new-controller/SKILL.md b/.agents/skills/new-controller/SKILL.md new file mode 100644 index 000000000..c327c3fe4 --- /dev/null +++ b/.agents/skills/new-controller/SKILL.md @@ -0,0 +1,270 @@ +--- +name: new-controller +description: Create a new ORC controller for an OpenStack resource. Use when adding support for a new OpenStack resource type (e.g., LoadBalancer, FloatingIP). +disable-model-invocation: true +--- + +# Create New Controller + +Create a new ORC controller for an OpenStack resource. + +**IMPORTANT**: Complete ALL steps in order. Do not stop after implementing TODOs - you must also write E2E tests and run them. Ask the user for `E2E_OSCLOUDS` path if needed to run tests. + +## Prerequisites + +Ask the user one by one about: +1. What OpenStack resource to create (e.g., "VolumeBackup") +2. Which service it belongs to (compute, network, blockstorage, identity, image) +3. Does it need polling for availability or deletion? (i.e., does the resource have intermediate provisioning states like PENDING_CREATE, BUILD, etc.) +4. Any dependencies on other ORC resources (required, optional, or import-only)? +5. Is there a similar existing controller to use as reference? (e.g., Listener for LoadBalancer) +6. Do they have `E2E_OSCLOUDS` path to a clouds.yaml for running E2E tests locally? (If not, local E2E testing will be skipped) +7. Any additional requirements or constraints? (e.g., cascade delete support, special validation rules, immutability requirements) + +## Step 1: Research the OpenStack Resource + +**Before scaffolding**, research the resource to understand the exact field names: + +1. **Read the gophercloud struct** to get exact field names: +```bash +go doc . +go doc .CreateOpts +``` + +2. **Look at a similar existing controller** for patterns (if user provided one): + - Check their `*_types.go` for API structure + - Check their `actuator.go` for implementation patterns + +3. **Note the exact field names** from gophercloud - use these when defining API types: + - If gophercloud has `VipSubnetID`, name the ORC field `VipSubnetRef` (not just `SubnetRef`) + - If gophercloud has `FlavorID`, name the ORC field `FlavorRef` + - Preserve prefixes like `Vip`, `Source`, `Destination` etc. + +## Step 2: Run Scaffolding Tool + +**IMPORTANT**: Build a single scaffolding command using the user's answers and the flags reference below. Run it exactly ONCE (user will be prompted to approve). + +Use the field names discovered in Step 1 to inform your implementation later. + +### Scaffolding Flags Reference + +**Required flags:** + +| Flag | Description | Example | +|------|-------------|---------| +| `-kind` | The Kind of the new resource (PascalCase) | `VolumeBackup`, `FloatingIP` | +| `-gophercloud-client` | The gophercloud function to instantiate a client | `NewBlockStorageV3`, `NewNetworkV2` | +| `-gophercloud-module` | Full gophercloud module import path | `github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/backups` | + +**Optional flags:** + +| Flag | Description | Default | +|------|-------------|---------| +| `-gophercloud-type` | The gophercloud struct type name | Same as `-kind` | +| `-openstack-json-object` | Object name in OpenStack JSON responses | snake_case of kind (e.g., `volume_backup`) | +| `-available-polling-period` | Polling period in seconds while waiting for resource to become available | `0` (available immediately) | +| `-deleting-polling-period` | Polling period in seconds while waiting for resource to be deleted | `0` (deleted immediately) | +| `-required-create-dependency` | Required dependency for creation (can repeat flag for multiple) | none | +| `-optional-create-dependency` | Optional dependency for creation (can repeat flag for multiple) | none | +| `-import-dependency` | Dependency for import filter (can repeat flag for multiple) | none | +| `-interactive` | Run in interactive mode | `true` (set to `false` for scripted use) | + +### Common Gophercloud Clients + +| Service | Client Function | Module Path Prefix | +|---------|-----------------|-------------------| +| Compute | `NewComputeV2` | `github.com/gophercloud/gophercloud/v2/openstack/compute/v2/...` | +| Network | `NewNetworkV2` | `github.com/gophercloud/gophercloud/v2/openstack/networking/v2/...` | +| Block Storage | `NewBlockStorageV3` | `github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/...` | +| Identity | `NewIdentityV3` | `github.com/gophercloud/gophercloud/v2/openstack/identity/v3/...` | +| Image | `NewImageV2` | `github.com/gophercloud/gophercloud/v2/openstack/image/v2/...` | + +### Example Command (for reference only - build your own based on user input) + +```bash +# Example with dependencies - adapt based on user's answers +go run ./cmd/scaffold-controller -interactive=false \ + -kind=Port \ + -gophercloud-client=NewNetworkV2 \ + -gophercloud-module=github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports \ + -required-create-dependency=Network \ + -optional-create-dependency=Subnet \ + -optional-create-dependency=SecurityGroup \ + -import-dependency=Network +``` + +After scaffolding completes, run code generation: + +```bash +make generate +``` + +Commit the scaffolding with the command used: + +```bash +git add . +git commit -m "$(cat <<'EOF' +Scaffolding for the VolumeBackup controller + +$ go run ./cmd/scaffold-controller -interactive=false \ + -kind=VolumeBackup \ + -gophercloud-client=NewBlockStorageV3 \ + -gophercloud-module=github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/backups +EOF +)" +``` + +## Step 3: Register with Resource Generator + +Add the new resource to `cmd/resource-generator/main.go` in the `resources` slice: + +```go +var resources []templateFields = []templateFields{ + // ... existing resources (keep alphabetically sorted) ... + { + Name: "VolumeBackup", + }, +} +``` + +Then regenerate to create the `zz_generated.*.go` files: + +```bash +make generate +``` + +## Step 4: Add OpenStack Client to Scope + +Update these files in `internal/scope/`: + +### scope.go +Add interface method: +```go +NewYourResourceClient() (osclients.YourResourceClient, error) +``` + +### provider.go +Implement the constructor: +```go +func (s *providerScope) NewYourResourceClient() (osclients.YourResourceClient, error) { + return osclients.NewYourResourceClient(s.provider) +} +``` + +### mock.go +Add mock client field and implementation for testing. + +## Step 5: Register Controller + +Add to `cmd/manager/main.go`: + +```go +import ( + yourresourcecontroller "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/yourresource" +) + +// In controllers slice: +controllers := []interfaces.Controller{ + // ... + yourresourcecontroller.New(scopeFactory), +} +``` + +## Step 6: Implement TODOs + +**Reference Documentation**: For detailed patterns and rationale, see: +- `website/docs/development/controller-implementation.md` - Progressing condition, ReconcileStatus, error handling, dependencies +- `website/docs/development/api-design.md` - Filter, ResourceSpec, ResourceStatus conventions +- `website/docs/development/coding-standards.md` - Code organization, naming, logging + +Find all scaffolding TODOs: + +```bash +grep -r "TODO(scaffolding)" api/v1alpha1/ internal/controllers// +``` + +### API Types (api/v1alpha1/_types.go) + +Use the exact field names from gophercloud discovered in Step 1. + +Define: +- `ResourceSpec` - Creation parameters with validation markers +- `Filter` - Import filter with `MinProperties:=1` +- `ResourceStatus` - Observed state fields + +### Actuator (internal/controllers//actuator.go) + +Implement: +- `CreateResource()` - Build CreateOpts, call OpenStack API +- `DeleteResource()` - Call delete API +- `ListOSResourcesForImport()` - Apply filter to list results +- `ListOSResourcesForAdoption()` - Match by spec fields +- `GetResourceReconcilers()` - (if resource supports updates) + +**ReconcileResourceActuator is optional**: The generic reconciler detects it via type assertion at runtime — there is no factory method to implement. To opt in, add the `reconcileResourceActuator` type alias and interface assertion in `actuator.go`, then implement `GetResourceReconcilers` on the actuator struct: + +```go +type ( + reconcileResourceActuator = interfaces.ReconcileResourceActuator[orcObjectPT, osResourceT] + resourceReconciler = interfaces.ResourceReconciler[orcObjectPT, osResourceT] +) + +var _ reconcileResourceActuator = myActuator{} + +func (actuator myActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.updateResource, + }, nil +} +``` + +If the resource is fully immutable (no mutable fields, no tags, no sub-resources), skip this entirely — the generic reconciler will not call it. + +### Implementation Patterns + +Follow the patterns in [patterns.md](patterns.md) when implementing the actuator and API types. + +### Status Writer (internal/controllers//status.go) + +Implement: +- `ResourceAvailableStatus()` - When is resource available? +- `ApplyResourceStatus()` - Map OpenStack fields to status + +## Step 7: Write and Run Tests + +**This step is required** - do not skip it. + +Complete the scaffolded API validation test in `test/apivalidations/_test.go` by adding tests for any resource-specific validations (enums, numeric ranges, tag uniqueness, format validation, cross-field rules). Look for `TODO(scaffolding)` markers in the generated file. + +Complete the E2E test stubs in `internal/controllers//tests/` and run tests following [testing](../testing/SKILL.md) + +## Checklist + +- [ ] Gophercloud struct researched (field names noted) +- [ ] Similar controller reviewed (if applicable) +- [ ] Scaffolding complete +- [ ] First `make generate` run +- [ ] Scaffolding committed +- [ ] Registered in resource-generator +- [ ] Second `make generate` run (creates zz_generated files) +- [ ] OpenStack client added to scope +- [ ] Controller registered in main.go +- [ ] API types implemented: + - [ ] Correct field names (matching OpenStack conventions) + - [ ] Stricter types where appropriate (IPvAny, custom tag types) + - [ ] Status constants in types.go (if resource has provisioning states) +- [ ] Actuator methods implemented: + - [ ] DeleteResource: no cascade unless explicitly requested + - [ ] DeleteResource: handles pending states and 409 Conflict (if resource has intermediate states) + - [ ] CreateResource includes tags with sorting (if applicable) + - [ ] Proper error classification (Terminal vs retryable) + - [ ] Descriptive dependency variable names +- [ ] Status writer implemented +- [ ] Update reconciler includes tags update (if tags are mutable) +- [ ] All TODOs resolved +- [ ] API validation tests complete (resource-specific validations added to scaffolded test) +- [ ] `make generate` runs cleanly +- [ ] `make lint` passes +- [ ] `make test` passes +- [ ] E2E tests written (including dependency tests if applicable) +- [ ] E2E tests passing diff --git a/.agents/skills/new-controller/patterns.md b/.agents/skills/new-controller/patterns.md new file mode 100644 index 000000000..b96bfe983 --- /dev/null +++ b/.agents/skills/new-controller/patterns.md @@ -0,0 +1,141 @@ +# ORC Controller Implementation Patterns + +Follow these principles when implementing controllers. See `website/docs/development/` for detailed rationale. + +## 1. Defensive Operations + +Avoid destructive defaults - require explicit user intent for dangerous operations. + +**Examples:** +- Never use cascade delete unless the user explicitly requests it (cascade removes all child resources) +- Don't auto-correct invalid states that might cause data loss +- Ask the user additional questions if required +- Prefer failing safely over making assumptions + +## 2. Resource Lifecycle Management + +Handle all states a resource can be in throughout its lifecycle. + +**For resources with intermediate provisioning states** (PENDING_CREATE, BUILD, PENDING_DELETE, etc.): +- Check the current state before attempting operations +- Wait for stable states before making changes +- Handle race conditions where state changes between check and action + +```go +// Example: Handle all states before deletion +switch resource.ProvisioningStatus { +case ProvisioningStatusPendingDelete: + return progress.WaitingOnOpenStack(progress.WaitingOnReady, deletingPollingPeriod) +case ProvisioningStatusPendingCreate, ProvisioningStatusPendingUpdate: + // Can't delete in pending state, wait for ACTIVE + return progress.WaitingOnOpenStack(progress.WaitingOnReady, availablePollingPeriod) +} + +// Example: Handle 409 Conflict (state changed between check and API call) +err := actuator.osClient.DeleteResource(ctx, resource.ID) +if orcerrors.IsConflict(err) { + return progress.WaitingOnOpenStack(progress.WaitingOnReady, deletingPollingPeriod) +} +``` + +**Note**: Resources without intermediate states (e.g., Flavor, Keypair) are created/deleted synchronously and don't need this handling. + +## 3. Deterministic State + +Ensure consistent, comparable state to enable reliable drift detection. + +**Principle**: Data should be normalized before storage and comparison so equivalent states produce identical representations. + +**Examples:** +- Sort lists before creation and comparison (tags, security group rules, allowed address pairs) +- Normalize strings (trim whitespace, consistent casing where appropriate) +- Use canonical forms for complex types + +```go +// Example: Sort tags for consistent comparison +tags := make([]string, len(resource.Tags)) +for i := range resource.Tags { + tags[i] = string(resource.Tags[i]) +} +slices.Sort(tags) +createOpts.Tags = tags + +// Example: Compare with sorting (copy before sorting to avoid mutation) +desiredTags := make([]string, len(resource.Tags)) +copy(desiredTags, resource.Tags) +slices.Sort(desiredTags) + +currentTags := make([]string, len(osResource.Tags)) +copy(currentTags, osResource.Tags) +slices.Sort(currentTags) + +if !slices.Equal(desiredTags, currentTags) { + updateOpts.Tags = &desiredTags +} +``` + +**Note**: Import `"slices"` when using sorting/comparison functions. + +## 4. Error Classification + +Distinguish between errors that can be retried vs those requiring user action. + +| Error Type | When to Use | Behavior | +|------------|-------------|----------| +| **Retryable** (default) | Transient issues (network, API unavailable) | Automatic retry with backoff | +| **Terminal** | Invalid configuration, bad input, permission denied | No retry until spec changes | + +Use `orcerrors.IsRetryable(err)` to check; wrap non-retryable errors with `orcerrors.Terminal()`. See AGENTS.md "Error Classification" for the code pattern. + +## 5. Dependency Timing + +Resolve dependencies as late as possible, as close to the point of use as possible. Only fetch a dependency when you actually need its ID for the current operation. + +- A Subnet depends on Network for creation, but not for import by ID or deletion +- Don't require recreating a deleted Network just to delete a Subnet whose `status.ID` is already set +- Only fetch optional dependencies conditionally (`if resource.SubnetRef != nil`) + +For detailed implementation: [add-dependency](../add-dependency/SKILL.md) + +## 6. Code Clarity + +Write self-documenting code through naming and organization. + +**Naming**: Use descriptive names that prevent ambiguity: +- `vipSubnetDependency` not `subnetDependency` (when multiple subnet types possible) +- `sourcePortDependency` vs `destinationPortDependency` +- `memberNetworkDependency` vs `externalNetworkDependency` + +**Organization**: Define constants and types where they're most accessible: +- Status constants: prefer using constants from gophercloud if available +- Only define constants in ORC's `types.go` if gophercloud doesn't provide them +- Internal helpers in `actuator.go` + +```go +// Prefer gophercloud constants when available: +import "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports" +if osResource.Status == ports.StatusActive { ... } + +// Only define in types.go if gophercloud doesn't have them: +const ( + ProvisioningStatusActive = "ACTIVE" + ProvisioningStatusPendingCreate = "PENDING_CREATE" + ProvisioningStatusError = "ERROR" +) +``` + +## 7. API Safety + +Design APIs that prevent invalid states through types and validation. + +**Use stricter types** where OpenStack provides specific formats: +- `IPvAny` for IP addresses (validates format) +- `OpenStackName` for resource names - but check the specific OpenStack project for exact limits (e.g., Keystone names max 64 chars, Neutron names max 255 chars) +- Custom types with validation (e.g., tag types with length limits) + +**Note**: Always check how fields are defined in the related OpenStack project to determine correct validation constraints. + +**Add validation markers** to catch errors early: +- `+kubebuilder:validation:MinLength`, `MaxLength` +- `+kubebuilder:validation:Pattern` for format constraints +- `+kubebuilder:validation:XValidation` for cross-field rules diff --git a/.agents/skills/proposal/SKILL.md b/.agents/skills/proposal/SKILL.md new file mode 100644 index 000000000..b735c31a6 --- /dev/null +++ b/.agents/skills/proposal/SKILL.md @@ -0,0 +1,194 @@ +--- +name: proposal +description: Write an enhancement proposal for a new ORC feature. Use for significant new features, breaking changes, or cross-cutting architectural changes. +disable-model-invocation: true +--- + +# Write Feature Proposal + +Guide for creating a proposal for a new feature or enhancement in ORC. + +## When to Write an Enhancement + +Write an enhancement proposal when you want to: +- Add a significant new feature or capability +- Make breaking changes to existing APIs +- Deprecate or remove functionality +- Make cross-cutting architectural changes +- Change behavior that users depend on + +You do **not** need an enhancement for: +- Bug fixes +- Small improvements or refactoring +- Documentation updates +- Adding support for additional OpenStack resource fields +- Test improvements + +When in doubt, suggest opening a GitHub issue first to discuss whether an enhancement proposal is needed. + +## Enhancement Lifecycle + +Enhancements move through the following statuses: + +| Status | Description | +|--------|-------------| +| `implementable` | The enhancement has been approved and is ready for implementation | +| `implemented` | The enhancement has been fully implemented and merged | +| `withdrawn` | The enhancement is no longer being pursued | + +## Template and File Location + +Use the enhancement template at `enhancements/TEMPLATE.md`. + +For full process details, see `enhancements/README.md`. + +### Creating the Proposal File + +Simple enhancement (single file): +```bash +cp enhancements/TEMPLATE.md enhancements/your-feature-name.md +``` + +Enhancement with supporting files (images, diagrams): +```bash +mkdir enhancements/your-feature-name +cp enhancements/TEMPLATE.md enhancements/your-feature-name/your-feature-name.md +``` + +## Information to Gather from User + +Before writing a proposal, ask the user about: + +1. **Feature Overview** + - What OpenStack resource or capability does this involve? + - What problem does this solve for users? + - Is this a new controller, enhancement to existing controller, or infrastructure change? + +2. **Use Cases** + - Who will use this feature? (end users, operators, other controllers) + - What are the primary use cases? + - Are there edge cases to consider? + +3. **Dependencies** + - Does this depend on other ORC resources? + - Does this require new OpenStack API capabilities? + - Are there upstream dependencies (gophercloud, controller-runtime)? + +4. **Scope** + - Is this a minimal viable feature or full implementation? + - Are there phases or milestones to break this into? + - What's explicitly out of scope? + +5. **Testing** + - How is this going to be tested? + - Are there specific E2E test scenarios required? + - What OpenStack capabilities are needed for testing? + +6. **Existing Infrastructure** (for non-controller enhancements) + - What related functionality already exists in ORC? + - Are there existing endpoints, ports, or configurations to integrate with? + - What frameworks/libraries does ORC already use for this area? + +## Research Phase + +Before writing the proposal, research the relevant area: + +- **OpenStack API & gophercloud**: Read the API docs, check gophercloud support, note async operations +- **Existing ORC patterns**: Look at similar controllers or infrastructure code for patterns to follow +- **Dependencies**: Map ORC resource dependencies (required vs optional, deletion guards) +- **Current implementation**: For infrastructure enhancements, read the actual code to verify technical details (ports, endpoints, framework capabilities) + +## Filling Out the Template + +Read the template at `enhancements/TEMPLATE.md` and fill in each section: + +| Section | What to Include | +|---------|-----------------| +| **Metadata table** | Status (`implementable`), author, dates, tracking issue (TBD initially) | +| **Summary** | 1-2 paragraph overview of the enhancement | +| **Motivation** | Why this is needed, who benefits, links to issues | +| **Goals** | Specific, measurable objectives | +| **Non-Goals** | What's explicitly out of scope | +| **Proposal** | Detailed solution with API examples | +| **Risks and Edge Cases** | What could go wrong, mitigations (see risk checklist below) | +| **Alternatives Considered** | Other approaches and why rejected | +| **Implementation History** | Timeline of major milestones | + +### For New Controller Proposals + +**Note**: New controllers following existing patterns typically don't need an enhancement proposal. Only write a proposal if the controller requires new patterns or architectural changes. + +If a proposal is needed, in the **Proposal** section, include: + +```yaml +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ResourceName +metadata: + name: example +spec: + cloudCredentialsRef: + secretName: openstack-credentials + cloudName: openstack + resource: + # Required fields with descriptions + # Optional fields with descriptions + import: + filter: + # Filter fields +status: + id: "uuid" + conditions: [...] + resource: + # Observed state fields +``` + +Also describe: +- Controller behavior (creation, updates, deletion) +- Dependencies (required vs optional, deletion guards) +- Mutable vs immutable fields + +### Risk Checklist + +Address each of these in the **Risks and Edge Cases** section: + +| Risk Category | Questions to Answer | +|---------------|---------------------| +| **API compatibility** | Will this break existing users? Are metric/label names stable? | +| **Security** | Are there security implications? (Often N/A for read-only features) | +| **Performance** | Could this impact controller performance at scale? | +| **Error handling** | What happens when things fail? | +| **Upgrade/downgrade** | How does this affect users upgrading or downgrading ORC? | +| **OpenStack compatibility** | Does this work across different OpenStack versions? (N/A for K8s-only) | +| **Interaction with existing features** | Could this conflict with existing behavior? | + +### Before Submitting + +Verify internal consistency (anything referenced in one section is defined elsewhere), technical accuracy (check against actual code), and that examples are complete. + +## Submission Process + +1. **Fill out the template** with proposal details +2. **Open a pull request** with title: `Enhancement: Add support for feature X` +3. **Iterate based on feedback** - Discussion happens on the PR +4. **Create a tracking issue** once merged - Label with `enhancement` and link in metadata + +## Review Process + +- Any community member can propose an enhancement +- Maintainers review proposals and provide feedback on the PR +- Enhancements are approved using lazy consensus (typically one week review period) +- The enhancement author is typically expected to drive implementation + +## Checklist + +- [ ] Confirmed enhancement proposal is needed (not just a bug fix or small improvement) +- [ ] Gathered feature requirements from user +- [ ] Researched relevant areas (OpenStack API, gophercloud, or existing infrastructure) +- [ ] Reviewed similar implementations in ORC +- [ ] Copied template to `enhancements/` +- [ ] Filled in all template sections +- [ ] Addressed all items in risk checklist +- [ ] Documented alternatives considered +- [ ] Verified internal consistency (references match definitions) +- [ ] Verified technical accuracy against codebase +- [ ] Opened PR for review diff --git a/.agents/skills/release-notes/SKILL.md b/.agents/skills/release-notes/SKILL.md new file mode 100644 index 000000000..f2afc0076 --- /dev/null +++ b/.agents/skills/release-notes/SKILL.md @@ -0,0 +1,225 @@ +--- +name: release-notes +description: Draft release notes for a new ORC version. Use when preparing a release to generate changelog and GitHub release body from git history. +disable-model-invocation: true +--- + +# Draft ORC Release Notes + +Guide for drafting release notes when preparing a new ORC release. + +## When to Use + +Use this skill when: +- Preparing a new ORC release +- The user asks to draft or write release notes +- The user asks to prepare a changelog entry + +## Step 1: Gather Release Parameters + +Ask the user for: +1. **New version number** (e.g., `v2.5.0`) +2. **Release date** (default: today) +3. **Release branch** (optional): The branch from which the release will be cut. Defaults to `HEAD`. When the release is cut from a different branch (e.g., `release-2.0`), use that branch as the upper bound of the commit range instead of `HEAD`. Release notes may be written on `main` even though the release is cut from a release branch. + +Then determine the previous release tag automatically: +```bash +git tag --sort=-v:refname | head -1 +``` + +## Step 2: Collect Git History + +Run these commands to gather the raw data. Replace `` with the previous tag and `` with the release branch (e.g., `upstream/release-2.0`) or `HEAD` if releasing from the current branch: + +```bash +# Full commit log +git log .. --oneline + +# Contributors with commit counts +git shortlog -sne .. + +# New controller directories (compare directory listings) +diff <(git ls-tree -d --name-only internal/controllers/ | sort) \ + <(git ls-tree -d --name-only internal/controllers/ | sort) \ + | grep '^>' + +# All authors who ever contributed before this release +git log --format='%aN' | sort -u > /tmp/old-contributors.txt + +# Authors in this release +git log .. --format='%aN' | sort -u > /tmp/new-contributors.txt + +# First-time contributors +comm -13 /tmp/old-contributors.txt /tmp/new-contributors.txt +``` + +For each first-time contributor, find the PR number of their first contribution: +```bash +git log .. --author="" --oneline --reverse | head -1 +``` +Then look up the corresponding PR number from the merge commit message (format: `Merge pull request #NNN`). + +> **Note**: When using a release branch, make sure to fetch it first (e.g., `git fetch upstream release-2.0`). The merge commit on the release branch may reference a backport PR number rather than the original PR. Use the original PR number from `main` for release notes since that's where the review and discussion happened. + +## Step 3: Categorize Changes + +Review every commit and sort into sections. Use these rules: + +### New controllers +Commits that add a new controller directory under `internal/controllers/`. Format: +``` +- : Manage +``` +Examples: +- `Keypair: Manage Nova SSH keypairs` +- `Volume: Manage Cinder block storage volumes` +- `Domain: Manage Keystone identity domains` + +### New features +Feature additions or enhancements to existing controllers or infrastructure. When scoped to a specific controller, prefix with the controller name and colon: +``` +- : +``` +Examples: +- `Server: Added ability to specify SSH keypair` +- `Added support for generating and publishing OLM bundle images` + +### Bug fixes +Bug fixes, especially those referencing GitHub issues. Include the issue link when available: +``` +- (Fixes [#NNN](https://github.com/k-orc/openstack-resource-controller/issues/NNN)) +``` +Examples: +- `Allow to use application credentials with access rules (Fixes [#596](https://github.com/k-orc/openstack-resource-controller/issues/596))` +- `Documentation: Fixed examples in getting-started guide` + +### Breaking changes +API incompatibilities or behavioral changes that require user action. Only include this section if there are breaking changes. List the specific type/field changes. + +### Update considerations +Important information users need to know when upgrading. Only include this section when relevant (e.g., new minimum OpenStack version requirements). + +### Infrastructure improvements +Group related items. Common categories: +- Go version bumps +- Dependency bumps (group into a single bullet: k8s libs, controller-runtime, gophercloud) +- CI changes (OpenStack version support, new test infrastructure) +- Documentation improvements +- Tooling changes + +### Commits to skip +Do NOT include in release notes: +- Changes related to newly introduced controllers: if a controller is new in this release, its features and bug fixes are already implied by the "New controllers" entry and must not be duplicated in "New features" or "Bug fixes" +- Dependabot/automated dependency bumps (summarize as a single infrastructure bullet) +- Merge commits +- Code style fixes, typo fixes, linting fixes +- Internal refactoring with no user-visible impact + +## Step 4: Write the Opening Summary + +The opening summary is optional. Include one when: +- The release has a strong unifying theme +- There is a major new capability worth highlighting + +Format: 1-2 sentences before the first section heading. + +Example from v2.3.0: +> This release brings support for updating resources after creation for all relevant controllers. You can now modify your OpenStack infrastructure in-place without recreating resources, enabling true lifecycle management for production workloads. + +## Step 5: Produce Two Outputs + +### Output 1: GitHub Release Body + +This is the markdown body for the GitHub release (used with `gh release create`). + +Template: +```markdown +## What's Changed + + + +### New controllers + +- Kind1: Description +- Kind2: Description + +### New features + +- Controller: Feature description +- Feature description + +### Bug fixes + +- Fix description (Fixes [#NNN](https://github.com/k-orc/openstack-resource-controller/issues/NNN)) + +### Infrastructure improvements + +- Category: Description + +## New Contributors + +- @username made their first contribution in [#NNN](https://github.com/k-orc/openstack-resource-controller/pull/NNN) + +**Full Changelog**: [...](https://github.com/k-orc/openstack-resource-controller/compare/...) +``` + +Notes: +- Omit any section that has no entries (e.g., skip "Breaking changes" if there are none) +- The "New Contributors" section lists first-time contributors with their GitHub username and first PR +- The "Full Changelog" link uses the GitHub compare URL between the two tags + +### Output 2: Changelog Entry + +This is prepended to `website/docs/changelog.md`, right after the `# Changelog` heading. + +Template: +```markdown +## v. - , + + + +### New controllers + +- Kind1: Description + +### New features + +- Feature description + +### Bug fixes + +- Fix description (Fixes [#NNN](https://github.com/k-orc/openstack-resource-controller/issues/NNN)) + +### Infrastructure improvements + +- Description +``` + +Notes: +- The heading uses `v.` (no patch version) with the full date +- No "New Contributors" or "Full Changelog" sections +- Otherwise identical content to the GitHub release body + +## Step 6: Review Checklist + +Before presenting the draft to the user, verify: + +- [ ] All new controller directories have corresponding entries in "New controllers" +- [ ] All GitHub issue references use the correct issue number and full URL +- [ ] First-time contributors are identified with correct GitHub usernames and PR numbers +- [ ] Dependency bumps are summarized (not listed individually) +- [ ] The compare URL uses the correct previous and new tag names +- [ ] Sections with no entries are omitted entirely +- [ ] Each bullet is concise (one line, no multi-sentence descriptions) +- [ ] Controller-scoped items are prefixed with the controller name +- [ ] The changelog entry heading uses the short version (vX.Y) and the full date +- [ ] The opening summary (if included) accurately represents the release highlights + +## Style Guidelines + +- Use past tense for completed work ("Added", "Fixed", "Bumped") +- Capitalize the first word of each bullet +- End bullets without a period +- Group related changes into a single bullet when possible (especially dependency bumps) +- Use the OpenStack service name to describe new controllers (Nova, Neutron, Cinder, Keystone, Glance) +- Reference specific version numbers for dependency bumps (e.g., "gophercloud to v2.9.0") diff --git a/.agents/skills/review/SKILL.md b/.agents/skills/review/SKILL.md new file mode 100644 index 000000000..fc235d3c8 --- /dev/null +++ b/.agents/skills/review/SKILL.md @@ -0,0 +1,320 @@ +--- +name: review +description: Review ORC controller code for Kubernetes best practices and ORC conventions. Use after implementing or modifying a controller. +disable-model-invocation: true +--- + +# ORC Code Review Guide + +Review ORC controller code for correctness, Kubernetes best practices, and ORC conventions. Produce a structured report at the end. + +## Step 1: Identify Review Scope + +Determine what changed and which checklists apply: + +1. Run `git diff` (or `git diff --cached`, or diff against the base branch) to identify modified files. +2. Categorize changes by file type: + - `api/v1alpha1/*_types.go` -> API Types checklist + - `internal/controllers/*/controller.go` -> Controller Setup checklist + - `internal/controllers/*/actuator.go` -> Actuator Logic checklist + - `internal/controllers/*/status.go` -> Status Writer checklist + - `internal/controllers/*/tests/` -> Test Coverage checklist + - Any `.go` file -> Code Style checklist +3. Always apply the Kubernetes Best Practices checklist. +4. Read every changed file in full before reviewing. Also read surrounding context (e.g., the full `*_types.go` for the resource, even if only part changed). + +## Step 2: API Types (`*_types.go`) + +Review any `api/v1alpha1/*_types.go` file against these rules: + +### Structure + +- [ ] Three hand-written types exist: `ResourceSpec`, `Filter`, `ResourceStatus`. +- [ ] Top-level types (``, `Spec`, `Status`, `List`) are code-generated in `zz_generated.*` files and NOT hand-edited. +- [ ] `ResourceSpec` contains fields mapping to OpenStack create API parameters. +- [ ] `Filter` contains a subset of identifying fields, all optional pointers. +- [ ] `ResourceStatus` contains observed state from OpenStack. + +### Validation Markers + +- [ ] String fields use `+kubebuilder:validation:MinLength` / `MaxLength` constraints. +- [ ] Numeric fields use `+kubebuilder:validation:Minimum` / `Maximum` where appropriate. +- [ ] Enum types use `+kubebuilder:validation:Enum` listing all valid values. +- [ ] Filter structs have `+kubebuilder:validation:MinProperties:=1` (at least one criterion required). +- [ ] Slice fields have `+listType` annotations (`set` for unique items like tags, `atomic` for ordered/opaque lists, `map` with `+listMapKey` for keyed lists like conditions). + +### Immutability + +- [ ] Fully immutable resources (rare, e.g., ServerGroup) apply `+kubebuilder:validation:XValidation:rule="self == oldSelf"` at the struct level. +- [ ] Partially mutable resources apply `rule="self == oldSelf"` on individual immutable fields, leaving mutable fields unmarked. +- [ ] Immutability validation messages are descriptive (e.g., `"imageRef is immutable"`). + +### Field Conventions + +- [ ] `+required` fields use value types (e.g., `RAM int32`) but still have `json:"...,omitempty"`. +- [ ] `+optional` fields use pointer types (e.g., `*OpenStackName`, `*bool`) to distinguish "not set" from zero. +- [ ] In `ResourceStatus`, fields are `+optional` with pointers or plain strings with `omitempty`. +- [ ] Status string fields use `string` with `+kubebuilder:validation:MaxLength=1024`, not the strongly-typed wrapper. + +### Shared Types + +- [ ] Resource names use `OpenStackName` (not raw `string`). Check the specific OpenStack project for the correct max length (Keystone: 64 chars, Neutron: 255 chars, etc.). +- [ ] References to other ORC objects use `KubernetesNameRef` with a `Ref` suffix (e.g., `projectRef`, `networkRef`). +- [ ] References NEVER point to raw OpenStack resource IDs. OpenStack IDs appear only in status. +- [ ] IP addresses use `IPvAny`, CIDRs use `CIDR`, MACs use `MAC`. +- [ ] Neutron resources use shared types: `NeutronDescription`, `NeutronTag`, `FilterByNeutronTags`, `NeutronStatusMetadata`. +- [ ] Non-Neutron resources define their own tag types with appropriate length constraints. + +### Sub-resources + +- [ ] Nested sub-resources have separate Spec and Status types (e.g., `SecurityGroupRule` vs `SecurityGroupRuleStatus`). +- [ ] Sub-resource Status types include an `ID` field when the sub-resource has its own OpenStack ID. +- [ ] Complex cross-field validation uses `XValidation` rules on the sub-resource struct. + +## Step 3: Controller Setup (`controller.go`) + +### Basic Setup + +- [ ] RBAC markers are present and minimal (only the verbs actually needed). +- [ ] Controller name is lowercase, may contain hyphens, and is unique across all controllers. +- [ ] `GetName()` returns the controller name constant. +- [ ] `SetupWithManager` follows the standard pattern: builder -> watches -> dependency registration -> reconciler creation -> complete. + +### Dependencies + +- [ ] Dependencies are declared as **package-level variables**, not inside functions. +- [ ] `DeletionGuardDependency` is used when deleting the dependency would either fail or cause the dependent to fail. +- [ ] Regular `Dependency` (no deletion guard) is used for import-only dependencies and cases where OpenStack allows the deletion. +- [ ] Each dependency has a descriptive name (e.g., `vipSubnetDependency` not `subnetDependency` when multiple subnet types exist). +- [ ] Field path strings in dependency declarations match the actual API field paths. +- [ ] Extraction functions correctly handle nil checks for optional references. + +### Watches + +- [ ] Each dependency has a corresponding `Watches` call in `SetupWithManager`. +- [ ] Watch handlers use `predicates.NewBecameAvailable` to avoid unnecessary reconciles. +- [ ] Credential dependency watch is always registered. +- [ ] All dependency registrations use `errors.Join` with `AddToManager`. + +## Step 4: Actuator Logic (`actuator.go`) + +### Structure + +- [ ] Type aliases defined at the top of the file for `osResourceT`, actuator interfaces, and `helperFactory`. +- [ ] Compile-time interface assertions present (`var _ createResourceActuator = myActuator{}`). +- [ ] OS client interface defined locally with only the methods the actuator needs. +- [ ] Actuator struct holds the OS client and optionally `k8sClient` (when dependencies are used). + +### Resource Name + +- [ ] `getResourceName` helper exists: returns `spec.resource.name` if set, otherwise falls back to the ORC object name. + +### GetOSResourceByID + +- [ ] Wraps errors with `progress.WrapError`. +- [ ] Handles "not found" correctly (returns `nil` resource, not an error). + +### ListOSResourcesForAdoption + +- [ ] Returns `false` (second return value) when `spec.resource` is nil (no spec to match against). +- [ ] Builds client-side filters matching the **full** resource spec for accurate adoption. + +### ListOSResourcesForImport + +- [ ] Builds filters from the import filter spec only. +- [ ] All filter fields are mapped. + +### CreateResource + +- [ ] Translates ORC spec into OpenStack `CreateOpts` completely. +- [ ] **MUST NOT** perform any action after the Create API call (idempotency requirement). +- [ ] Any actions before Create are idempotent (Create may be called many times). +- [ ] Non-retryable errors are wrapped with `orcerrors.Terminal`. +- [ ] Lists (tags, etc.) are sorted before passing to Create for deterministic state. +- [ ] Finalizers on dependencies are added immediately before the Create call, not earlier. + +### DeleteResource + +- [ ] **MUST NOT** perform any action after the Delete API call. +- [ ] Handles "not found" gracefully (resource already deleted). +- [ ] For resources with intermediate states: checks provisioning status before deleting, handles 409 Conflict by waiting. +- [ ] Minimal dependency requirements -- does not require dependencies that aren't strictly needed for deletion. + +### ReconcileResourceActuator (if implemented) + +- [ ] `GetResourceReconcilers` returns reconciler functions for post-creation tasks (e.g., setting Neutron tags, handling mutable field updates). +- [ ] Reconcilers that modify the OpenStack resource return a `progress.ProgressStatus` to force a status refresh. +- [ ] Reconcilers are independent and don't rely on side effects of other reconcilers. +- [ ] `updateResource` is used only for general mutable field updates via the resource's Update API (building `UpdateOpts`, single API call). Operations using a separate API have a descriptive name (e.g., `reconcileExtraSpecs`, `reconcileSubports`, `reconcilePassword`, `updateRules`). +- [ ] Single-concern reconcilers return `nil` (not a terminal error) when `spec.resource` is nil. Only `updateResource` returns a terminal error for nil `spec.resource`. +- [ ] `CreateResource` does not duplicate work that is handled by a reconciler. The `CreateResource` contract forbids actions that can fail after creating the primary resource. + +### Error Handling + +- [ ] All errors from OpenStack API calls are checked. +- [ ] Non-retryable errors (400, invalid config) wrapped with `orcerrors.Terminal` and an appropriate `ConditionReason`. +- [ ] Transient errors (5xx, network) left as default (automatic retry with backoff). +- [ ] `ReconcileStatus` return values are **never discarded** -- always assigned and propagated. +- [ ] When wrapping errors, use `progress.WrapError(err)` (not bare `fmt.Errorf`). + +### Dependency Resolution + +- [ ] Dependencies resolved **as late as possible**, close to the point of use. +- [ ] Dependencies not required for deletion unless strictly necessary (e.g., don't require Network to delete a Subnet with `status.ID` already set). +- [ ] Dependencies not required for import-by-ID. +- [ ] `GetDependency` results checked: if `needsReschedule` is true, return early. +- [ ] Readiness predicate uses `orcv1alpha1.IsAvailable` (the standard helper from `api/v1alpha1/conditions.go`). `Status.ID` is always set before a resource becomes Available, so checking `dep.Status.ID != nil` separately is unnecessary. + +## Step 5: Status Writer (`status.go`) + +### Structure + +- [ ] Type aliases for `objectApplyT` and `statusApplyT` (SSA apply configuration types). +- [ ] Compile-time interface assertion for `ResourceStatusWriter`. + +### ResourceAvailableStatus + +- [ ] Returns `ConditionTrue` only when the resource is completely ready for use. +- [ ] Returns `ConditionFalse` when `osResource` is nil and no `status.ID` exists (not yet created). +- [ ] Returns `ConditionUnknown` when `osResource` is nil but `status.ID` exists (can't verify current state). +- [ ] For resources with intermediate states (BUILD, PENDING_CREATE): returns `ConditionFalse` until the resource reaches a stable, usable state (e.g., ACTIVE). +- [ ] For resources in ERROR state: returns `ConditionFalse`. + +### ApplyResourceStatus + +- [ ] Maps **all** OpenStack resource fields to ORC status fields. +- [ ] Zero/empty values handled correctly: only include swap, ephemeral, description, etc., when non-zero/non-empty. +- [ ] Does NOT attempt to preserve previous status when the OpenStack resource can't be fetched (status.resource is cleared intentionally). +- [ ] Pointer fields in status use `ptr.To()` for conversion. + +## Step 6: Kubernetes Best Practices + +### Conditions + +- [ ] **Progressing=True** means status doesn't yet reflect spec AND controller expects more reconciles. +- [ ] **Progressing=False** means the object will NOT be reconciled again until the spec changes. This covers both success (Available=True) and terminal errors. +- [ ] **Available=True** means the resource is ready for use by consumers. +- [ ] Condition reasons use defined constants from `orcv1alpha1` (e.g., `ConditionReasonInvalidConfiguration`, `ConditionReasonTransientError`). +- [ ] Conditions are not set directly by the actuator -- the generic reconciler handles this based on `ReconcileStatus` and `ResourceStatusWriter` return values. + +### Finalizers + +- [ ] Finalizers on dependency objects are added only immediately before the OpenStack create/update call that references them (not during initialization). +- [ ] Deletion guard finalizers are managed by `DeletionGuardDependency` -- the controller doesn't manually add/remove them. +- [ ] The controller's own finalizer is managed by the generic reconciler framework. + +### Server-Side Apply + +- [ ] Status is written via SSA apply configurations (not direct status updates). +- [ ] `GetApplyConfig` returns a fresh apply configuration each time. +- [ ] Status is written in a single SSA transaction per reconcile. + +### Resource Safety + +- [ ] No cascade deletes unless the user explicitly requested them. +- [ ] No auto-correction of invalid states that might cause data loss. +- [ ] Prefer failing safely over making assumptions. + +## Step 7: Code Style + +See AGENTS.md for conventions (import ordering, logging levels, pointer handling). Only flag deviations that affect correctness: + +- [ ] Generated files (`zz_generated.*`) are not hand-edited. +- [ ] `make generate` has been run after any API type changes. +- [ ] Constants from gophercloud are preferred over locally defined string constants (e.g., `ports.StatusActive` instead of `"ACTIVE"`). + +## Step 8: Test Coverage + +### E2E Test Directories + +For each controller, verify the following test directories exist under `internal/controllers//tests/`: + +| Required Test | Purpose | +|---------------|---------| +| `-create-minimal/` | Create with only required fields, verify status matches | +| `-create-full/` | Create with all fields populated | +| `-import/` | Import an existing OpenStack resource | +| `-import-error/` | Import with no matches, verify error handling | +| `-dependency/` | Test dependency waiting and deletion guard protection | + +| Conditional Test | When Required | +|------------------|---------------| +| `-update/` | Resource has mutable fields | +| `-import-dependency/` | Import filter references other ORC objects | + +### E2E Test Quality + +- [ ] Each test directory has a `README.md` describing each step. +- [ ] Step files use zero-padded numeric prefixes (`00-`, `01-`, etc.). +- [ ] Cloud credentials secret created via `TestStep` command (not a manifest) using `E2E_KUTTL_OSCLOUDS`. +- [ ] Assertions verify `status.resource` fields match the spec. +- [ ] Conditions (`Available`, `Progressing`) are asserted with correct `status`, `reason`, and `message`. +- [ ] Dependency tests verify: (1) waiting state with `Progressing=True`, (2) availability after dep created, (3) finalizer blocks dep deletion, (4) dep deleted after resource deleted. +- [ ] Update tests use `kubectl replace` (not KUTTL patch) to test field removal. +- [ ] CEL expressions (`celExpr`) used for complex assertions (e.g., checking `deletionTimestamp`, finalizer membership, field absence with `!has(...)`). + +### Unit / API Validation Tests + +- [ ] API validation tests exist at `test/apivalidations/_test.go` for non-trivial validation rules. +- [ ] Unit tests cover any complex helper logic. + +## Step 9: Produce Review Report + +After running through all applicable checklists, produce a structured report: + +### Report Format + +``` +## Review Summary + +**Scope**: +**Overall**: + +## Blockers +Items that MUST be fixed before merge. These are correctness issues, violations +of idempotency/safety invariants, or missing required functionality. + +- [file:line] Description of the issue and why it's a blocker. + +## Warnings +Items that SHOULD be fixed. These are convention violations, missing edge case +handling, or patterns that may cause issues in production. + +- [file:line] Description and recommendation. + +## Suggestions +Items that COULD be improved. Style preferences, minor optimizations, or +additional test coverage that would be nice to have. + +- [file:line] Description and suggestion. + +## Positive Observations +Notable good practices observed in the code (keep brief, 2-3 items max). +``` + +### Severity Guidelines + +**Blocker** -- any of: +- Violates CreateResource/DeleteResource idempotency invariant (actions after the API call) +- Incorrect Progressing/Available condition semantics (could cause reconciliation to hang) +- Missing `ReconcileStatus` propagation (discarded return value) +- Terminal error not marked terminal (infinite retry of unfixable error) +- Missing finalizer or finalizer added too early +- Security issue (RBAC too broad, secrets leaked in logs) +- Data loss risk (cascade delete without explicit user intent) + +**Warning** -- any of: +- Missing validation markers on API types +- Dependency resolved too early (unnecessary coupling) +- Missing error wrapping (`progress.WrapError`) +- Incomplete status mapping (fields not reflected in status) +- Missing E2E test for a standard scenario +- Wrong logging level +- Missing interface assertion + +**Suggestion** -- any of: +- Import ordering +- Naming could be more descriptive +- Additional test coverage beyond the standard set +- Code could be simplified +- Comment could be clearer diff --git a/.agents/skills/testing/SKILL.md b/.agents/skills/testing/SKILL.md new file mode 100644 index 000000000..317eb9998 --- /dev/null +++ b/.agents/skills/testing/SKILL.md @@ -0,0 +1,111 @@ +--- +name: testing +description: Run ORC tests (unit tests, linting, and E2E tests). Use after making changes to verify correctness. +disable-model-invocation: true +--- + +# ORC Testing Guide + +Run unit tests, linting, and E2E tests for ORC controllers. + +## Unit Tests and Linting + +Before running E2E tests, ensure code compiles and passes linting: + +```bash +make generate +make lint +make test +``` + +## E2E Test Prerequisites + +E2E tests require `E2E_OSCLOUDS` environment variable pointing to a `clouds.yaml` file containing cloud entries for regular and admin credentials. The cloud names are configurable via environment variables: + +| Variable | Description | Default | +|----------|-------------|--------| +| `E2E_OSCLOUDS` | Path to `clouds.yaml` | `/etc/openstack/clouds.yaml` | +| `E2E_OPENSTACK_CLOUD_NAME` | Cloud name for regular credentials | `devstack` | +| `E2E_OPENSTACK_ADMIN_CLOUD_NAME` | Cloud name for admin credentials | `devstack-admin-demo` | + +If the user did not provide `E2E_OSCLOUDS`, tell them local E2E testing will be skipped and they should run it manually later or in CI. + +## Running E2E Tests + +If `E2E_OSCLOUDS` is provided, execute each step in order: + +**Step 1: Create kind cluster (if not already running)** +```bash +# Check if cluster exists +kind get clusters + +# Create only if no cluster exists +kind create cluster +``` +If a cluster already exists, skip creation and proceed to Step 2. + +**Step 2: Verify cluster is ready** +```bash +kubectl get nodes +``` +Ensure node shows `Ready` status. + +**Step 3: Install CRDs** +```bash +kubectl apply -k config/crd --server-side +``` + +**Step 4: Stop any existing manager, rebuild, and start** +```bash +# Stop any existing manager to ensure we're running latest code +pkill -f orc-manager || true + +# Build and start fresh +go build -o /tmp/orc-manager ./cmd/manager +/tmp/orc-manager -zap-log-level 5 > /tmp/manager.log 2>&1 & +``` + +**Step 5: Wait for manager to start and verify it's running** +```bash +sleep 5 +ps aux | grep "[o]rc-manager" +``` +If no process found, check `/tmp/manager.log` for errors. + +**Step 6: Run E2E tests** +Replace `/path/to/clouds.yaml` with the actual path and `` with the controller name: +```bash +E2E_OSCLOUDS=/path/to/clouds.yaml E2E_KUTTL_DIR=internal/controllers//tests make test-e2e +``` + +**Step 7: If tests fail, review manager logs** +```bash +# Search for errors first (logs are verbose at level 5) +grep -i error /tmp/manager.log | tail -50 + +# Or view more context +tail -500 /tmp/manager.log +``` +Use these logs to diagnose and fix issues, then re-run the tests. + +**Step 8: Cleanup** +After tests pass (or when done debugging): +```bash +pkill -f "orc-manager" || true +kind delete cluster +rm -f /tmp/manager.log /tmp/orc-manager +``` + +## E2E Test Directory Structure + +Tests are located in `internal/controllers//tests/`: + +| Directory | Purpose | +|-----------|---------| +| `-create-minimal/` | Create with minimum required fields | +| `-create-full/` | Create with all fields | +| `-import/` | Import existing resource | +| `-import-error/` | Import with no matches | +| `-dependency/` | Test dependency waiting and deletion guards | +| `-import-dependency/` | Test import with dependency references | +| `-update/` | Test mutable field updates | diff --git a/.agents/skills/update-controller/SKILL.md b/.agents/skills/update-controller/SKILL.md new file mode 100644 index 000000000..f80d9601f --- /dev/null +++ b/.agents/skills/update-controller/SKILL.md @@ -0,0 +1,224 @@ +--- +name: update-controller +description: Update an existing ORC controller. Use when adding fields, making fields mutable, adding tag support, or improving error handling. +disable-model-invocation: true +--- + +# Update Existing Controller + +Guide for modifying an existing ORC controller. + +**Reference**: See `website/docs/development/` for detailed patterns and rationale. + +## Before Making Changes + +Research the resource before implementing changes: + +1. **Check gophercloud** for the resource's API: + ```bash + go doc .UpdateOpts + go doc .CreateOpts + ``` + +2. **Check existing controller** patterns: + - How are similar fields handled? + - Does the resource have intermediate provisioning states? + - How are tags updated (standard Update API or separate tags API)? + +3. **Check OpenStack API documentation** for: + - Field constraints (max lengths, allowed values) + - Mutability (can the field be updated after creation?) + +## Key Principles + +When updating controllers, follow the patterns in [patterns.md](../new-controller/patterns.md) + +## Common Update Scenarios + +### Adding a New Field to Spec + +1. **Update API types** in `api/v1alpha1/_types.go`: + - Add field to `ResourceSpec` + - Add corresponding field to `ResourceStatus` + - Add validation markers (`+kubebuilder:validation:*`) + +2. **Update actuator** in `internal/controllers//actuator.go`: + - Add field to `CreateOpts` in `CreateResource()` + - If mutable, add update logic in reconciler + +3. **Update status writer** in `internal/controllers//status.go`: + - Add field mapping in `ApplyResourceStatus()` + +4. **Regenerate**: + ```bash + make generate + ``` + +5. **Update tests** to cover the new field (add only what's relevant to your change): + - Unit tests in `internal/controllers//actuator_test.go` (if complex logic) + - E2E tests in `internal/controllers//tests/`: + - `create-full`: Set new field to non-default value and verify + - `create-minimal`: Verify default value behavior (if field has defaults) + - `update`: Test setting and unsetting the field (only if field is mutable) + - `*-dependency`: Test dependency behavior (only if adding a new dependency) + - `*import*`: Test import filtering (only if adding a new filter field) + +### Adding a New Filter Field + +1. Add field to `Filter` in `api/v1alpha1/_types.go` + +2. Update `ListOSResourcesForImport()` in actuator to apply the filter + +3. Add import test case + +### Making a Field Mutable + +1. Remove immutability validation from the field: + ```go + // Remove or update this validation + // +kubebuilder:validation:XValidation:rule="self == oldSelf" + ``` + +2. Implement `GetResourceReconcilers()` if not already present + +3. Add update handling to the `updateResource()` reconciler (or create it if not present). Follow the pattern in `internal/controllers/securitygroup/actuator.go` (or `trunk/actuator.go`): + - Build an `UpdateOpts` struct using `handleXXXUpdate()` helpers for each mutable field + - Use a `needsUpdate()` helper that serializes the opts to a map and checks `len() > 0` + - Call the Update API only if something changed, return `progress.NeedsRefresh()` + - Return terminal error if `spec.resource` is nil + + **Note**: Only use `updateResource` when the field is updated via the resource's standard Update API. If the field requires a different API (e.g., extra specs, subports, tags on networking resources), create a separate single-concern reconciler instead. See [Adding a Single-Concern Reconciler](#adding-a-single-concern-reconciler) below. + +4. Register in `GetResourceReconcilers()`: + ```go + return []resourceReconciler{ + actuator.updateResource, + }, nil + ``` + +### Adding a Single-Concern Reconciler + +When a mutable field uses a separate OpenStack API (not the resource's Update API), create a dedicated reconciler with a descriptive verb+noun name instead of adding logic to `updateResource`. + +**Examples**: `reconcileExtraSpecs` (flavor, volumetype), `reconcileSubports` (trunk), `reconcilePassword` (user), `updateRules` (securitygroup). + +Key differences from `updateResource`: + +- **Naming**: Use a descriptive name (e.g., `reconcileExtraSpecs`), not `updateResource`. +- **Nil guard**: Return `nil` when `spec.resource` is nil (not a terminal error). The terminal error pattern is reserved for `updateResource`. +- **Multiple API calls**: A single-concern reconciler may make multiple API calls (e.g., create some extra specs, delete others). This is an established pattern (see `reconcileSubports`, `updateRules`). +- **Idempotency**: Operations must be idempotent. If the reconciler fails partway through, the next reconciliation recomputes the diff from the current OpenStack state and retries only what's still needed. + +```go +func (actuator myActuator) reconcileExtraSpecs(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + resource := obj.Spec.Resource + if resource == nil { + return nil // Not a terminal error (unlike updateResource) + } + + // Compute desired vs current diff + // Make API calls (creates, updates, deletes) + // Return progress.NeedsRefresh() if any changes were made +} +``` + +Register alongside other reconcilers in `GetResourceReconcilers()`: +```go +return []resourceReconciler{ + actuator.updateResource, // general field updates via Update API + actuator.reconcileExtraSpecs, // single-concern: separate API +}, nil +``` + +**Do NOT duplicate work in `CreateResource`**. If a reconciler handles a concern (e.g., extra specs), do not also set that data in `CreateResource`. The `CreateResource` contract forbids actions that can fail after creating the primary resource. The reconciler will handle it on the first reconciliation after creation. + +### Adding a Dependency + +See [add-dependency](../add-dependency/SKILL.md) for detailed steps. + +### Improving DeleteResource + +For resources with intermediate provisioning states, ensure robust deletion: + +```go +func (actuator myActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + // Handle intermediate states + switch resource.ProvisioningStatus { + case ProvisioningStatusPendingDelete: + return progress.WaitingOnOpenStack(progress.WaitingOnReady, deletingPollingPeriod) + case ProvisioningStatusPendingCreate, ProvisioningStatusPendingUpdate: + // Can't delete in pending state, wait for ACTIVE + return progress.WaitingOnOpenStack(progress.WaitingOnReady, availablePollingPeriod) + } + + err := actuator.osClient.DeleteResource(ctx, resource.ID) + // Handle 409 (state changed between check and API call) + if orcerrors.IsConflict(err) { + return progress.WaitingOnOpenStack(progress.WaitingOnReady, deletingPollingPeriod) + } + return progress.WrapError(err) +} +``` + +**Important**: Never use cascade delete unless explicitly requested by the user. + +### Adding Tag Support + +**Note**: Tag handling varies by OpenStack service. Some services (e.g., block storage) include tags in the standard Update API, while others (e.g., networking) require a separate tags API and a dedicated reconciler. Check gophercloud for the specific resource. + +1. Add `Tags` field to spec and status: + ```go + // In ResourceSpec + // +kubebuilder:validation:MaxItems:=64 + // +listType=set + Tags []NeutronTag `json:"tags,omitempty"` + + // In ResourceStatus + // +listType=atomic + Tags []string `json:"tags,omitempty"` + ``` + +2. Sort tags before creation and comparison (use `slices.Sort` — see `patterns.md` §3 Deterministic State). + +3. Add a `handleTagsUpdate()` helper that sorts both desired and current tags, compares with `slices.Equal`, and sets `updateOpts.Tags` only if different. Copy before sorting to avoid mutating the original. + +4. Register `updateResource` (which calls `handleTagsUpdate`) in `GetResourceReconcilers()`. + +### Adding Status Constants + +For resources with provisioning states, prefer using constants from gophercloud when available. Only define constants in ORC's `types.go` if gophercloud doesn't provide them. + +```go +// Prefer gophercloud constants when available: +import "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers" +if osResource.ProvisioningStatus == loadbalancers.ProvisioningStatusActive { ... } + +// Only define in types.go if gophercloud doesn't have them: +const ( + MyResourceProvisioningStatusActive = "ACTIVE" + MyResourceProvisioningStatusPendingCreate = "PENDING_CREATE" + MyResourceProvisioningStatusError = "ERROR" +) +``` + +See also [patterns.md](../new-controller/patterns.md) for more details on this pattern. + +### Improving Error Handling + +See [patterns.md](../new-controller/patterns.md) §4 Error Classification. Wrap non-retryable errors with `orcerrors.Terminal`; leave transient errors as-is for automatic retry. + +## Testing Changes + +Follow [testing](../testing/SKILL.md) for running unit tests, linting, and E2E tests. + +## Checklist + +- [ ] API types updated with proper validation +- [ ] Actuator updated (create/update logic) +- [ ] Status writer updated +- [ ] `make generate` runs cleanly +- [ ] `make lint` passes +- [ ] `make test` passes +- [ ] E2E tests updated/added +- [ ] E2E tests passing +- [ ] Unit tests added (if complex logic) diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 000000000..e27921b0b --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,14 @@ +{ + "permissions": { + "allow": [ + "Bash(go mod tidy:*)", + "Bash(make generate:*)", + "Bash(go build:*)", + "Bash(go fmt:*)", + "Bash(go doc:*)", + "Bash(make test:*)" + ], + "deny": [], + "ask": [] + } +} diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 000000000..2b7a412b8 --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..22eecab4f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +# Generated API types +api/v1alpha1/zz_generated.*.go linguist-generated + +# Generated OpenAPI schema +cmd/models-schema/zz_generated.openapi.go linguist-generated + +# Generated controller scaffolding +internal/controllers/**/zz_generated.*.go linguist-generated + +# Generated mock clients +internal/osclients/mock/*.go linguist-generated + +# Generated Kubernetes client libraries +pkg/clients/**/*.go linguist-generated + +# Generated CRD manifests +config/crd/bases/*.yaml linguist-generated + +# Generated documentation +website/docs/development/godoc/*.md linguist-generated +website/docs/crd-reference.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 59eec8232..7162b2299 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -6,6 +6,10 @@ body: attributes: value: | Thanks for taking the time to fill out this feature request! + + **Note:** For significant new features or architectural changes, consider writing an + [enhancement proposal](https://github.com/k-orc/openstack-resource-controller/tree/main/enhancements) + instead of or in addition to this issue. - type: textarea id: request attributes: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4cbbc172e..42418aa7e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,6 +9,8 @@ updates: schedule: interval: "weekly" day: "monday" + cooldown: + default-days: 7 target-branch: main groups: all-github-actions: @@ -23,6 +25,8 @@ updates: schedule: interval: "weekly" day: "monday" + cooldown: + default-days: 7 target-branch: main groups: all-go-mod-patch-and-minor: @@ -39,14 +43,16 @@ updates: - dependency-name: "k8s.io/*" update-types: ["version-update:semver-major", "version-update:semver-minor"] ## main branch config ends here -## release-1.0 branch config starts here +## release-2.0 branch config starts here # github-actions - directory: "/" package-ecosystem: "github-actions" schedule: interval: "weekly" day: "monday" - target-branch: release-1.0 + cooldown: + default-days: 7 + target-branch: release-2.0 groups: all-github-actions: patterns: [ "*" ] @@ -60,7 +66,9 @@ updates: schedule: interval: "weekly" day: "monday" - target-branch: release-1.0 + cooldown: + default-days: 7 + target-branch: release-2.0 groups: all-go-mod-patch-and-minor: patterns: [ "*" ] @@ -75,7 +83,4 @@ updates: # Ignore k8s major and minor bumps and its transitives modules - dependency-name: "k8s.io/*" update-types: ["version-update:semver-major", "version-update:semver-minor"] - # Below dependencies require a newer version of go: - - dependency-name: "github.com/onsi/gomega" - - dependency-name: "golang.org/x/text" -## release-1.0 branch config ends here +## release-2.0 branch config ends here diff --git a/.github/labeler.yml b/.github/labeler.yml index 88ebd919e..c7538490d 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,2 +1,4 @@ v1.0: - base-branch: 'release-1.0' +v2.0: +- base-branch: 'release-2.0' diff --git a/.github/labels.yaml b/.github/labels.yaml index 7541d0f20..6552f0931 100644 --- a/.github/labels.yaml +++ b/.github/labels.yaml @@ -1,9 +1,12 @@ -- color: '30ABB9' - description: This PR will be backported to v1.0 - name: backport-v1.0 - color: '30ABB9' description: This PR targets v1.0 name: v1.0 +- color: 'D97706' + description: This PR will be backported to v2.0 + name: backport-v2.0 +- color: 'D97706' + description: This PR targets v2.0 + name: v2.0 - color: 'BCF611' description: A good issue for first-time contributors @@ -26,3 +29,6 @@ - color: 'C2E0C6' description: Documentation name: docs +- color: 'A2EEEF' + description: Enhancement proposal + name: enhancement diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index ddd61d4fb..25a5ed2e5 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -1,45 +1,49 @@ name: Pull Request backporting on: + # zizmor: ignore[dangerous-triggers] only runs on merged PRs, never checks out code pull_request_target: types: - closed - labeled -permissions: - contents: read - pull-requests: write +permissions: {} jobs: - backport_v1_0: - name: "Backport to v1.0" + backport_v2_0: + name: "Backport to v2.0" + permissions: + contents: read + pull-requests: write # Only react to merged PRs for security reasons. # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. if: > github.event.pull_request.merged && ( github.event.action == 'closed' - && contains(github.event.pull_request.labels.*.name, 'backport-v1.0') + && contains(github.event.pull_request.labels.*.name, 'backport-v2.0') || ( github.event.action == 'labeled' - && contains(github.event.label.name, 'backport-v1.0') + && contains(github.event.label.name, 'backport-v2.0') ) ) runs-on: ubuntu-latest steps: - name: Generate a token from the orc-backport-bot github-app id: generate_token - uses: getsentry/action-github-app-token@a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef + uses: getsentry/action-github-app-token@5c1e90706fe007857338ac1bfbd7a4177db2f789 # tag=v4.0.0 with: - app_id: ${{ secrets.BACKPORT_APP_ID }} - private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} + app_id: ${{ secrets.BACKPORT_APP_ID }} # zizmor: ignore[secrets-outside-env] + private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] - name: Backporting if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') + || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 + || contains(github.event.label.name, 'semver:minor') + uses: kiegroup/git-backporting@08da0b07ef2330d189f6074ec8db736b3aa9f465 # tag=v4.9.1 with: - target-branch: release-1.0 + target-branch: release-2.0 pull-request: ${{ github.event.pull_request.url }} auth: ${{ steps.generate_token.outputs.token }} no-squash: true @@ -53,18 +57,16 @@ jobs: GH_REPO: ${{ github.repository }} NUMBER: ${{ github.event.pull_request.number }} BODY: > - Failed to backport PR to `release-1.0` branch. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. + Failed to backport PR to `release-2.0` branch. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. - name: Report an error if backport unsupported labels if: > contains(github.event.pull_request.labels.*.name, 'semver:major') - || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:major') - || contains(github.event.label.name, 'semver:minor') run: gh pr comment "$NUMBER" --body "$BODY" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} NUMBER: ${{ github.event.pull_request.number }} BODY: > - Labels `semver:major` and `semver:minor` block backports to the branch `release-1.0`. + Label `semver:major` blocks backports to the branch `release-2.0`. diff --git a/.github/workflows/check-pr-labels.yaml b/.github/workflows/check-pr-labels.yaml index 8d3cdde07..cf00b09e8 100644 --- a/.github/workflows/check-pr-labels.yaml +++ b/.github/workflows/check-pr-labels.yaml @@ -1,7 +1,7 @@ name: Ready on: merge_group: - pull_request_target: + pull_request: types: - labeled - opened @@ -9,6 +9,8 @@ on: - synchronize - unlabeled +permissions: {} + jobs: hold: if: github.event.pull_request.merged == false diff --git a/.github/workflows/container_image.yaml b/.github/workflows/container_image.yaml index c315a3e50..d970ac680 100644 --- a/.github/workflows/container_image.yaml +++ b/.github/workflows/container_image.yaml @@ -17,18 +17,31 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 with: # Required for git describe to generate correct output for populating # build variables fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # tag=v4.2.0 - - run: | - docker login -u="${{ secrets.QUAY_USERNAME }}" -p="${{ secrets.QUAY_TOKEN }}" quay.io + - name: Build and push images + run: | + docker login -u="${{ secrets.QUAY_USERNAME }}" -p="${{ secrets.QUAY_TOKEN }}" quay.io # zizmor: ignore[secrets-outside-env] # Ensure we source identical build arguments for both builds source hack/version.sh && version::get_git_vars && version::get_build_date && \ make docker-buildx IMG=${{ env.image_tag_branch }} && \ - make docker-buildx IMG=${{ env.image_tag_commit }} DOCKER_BUILD_ARGS="--annotation quay.expires-after=4w" + make docker-buildx IMG=${{ env.image_tag_commit }} + + - name: Set expiration on commit image + env: + QUAY_OAUTH_TOKEN: ${{ secrets.QUAY_OAUTH_TOKEN }} # zizmor: ignore[secrets-outside-env] + run: | + EXPIRATION=$(($(date -u +%s) + 2419200)) + curl -sf -X PUT \ + -H "Authorization: Bearer ${QUAY_OAUTH_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"expiration\": $EXPIRATION}" \ + "https://quay.io/api/v1/repository/orc/openstack-resource-controller/tag/commit-${GITHUB_SHA::7}" diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index da07b7eee..3ca389883 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -14,32 +14,41 @@ jobs: fail-fast: false matrix: include: + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "flamingo" openstack_version: "stable/2025.2" ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" env: image_tag: virtual-registry.k-orc.cloud/ci:commit-${GITHUB_SHA::7} runs-on: ubuntu-${{ matrix.ubuntu_version }} steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: false - name: Deploy devstack - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # tag=v0.19 with: enable_workaround_docker_io: 'false' branch: ${{ matrix.openstack_version }} - enabled_services: "openstack-cli-server" + enabled_services: "openstack-cli-server,neutron-trunk,neutron-port-trusted-vif,neutron-uplink-status-propagation" + conf_overrides: | + enable_plugin neutron https://github.com/openstack/neutron ${{ matrix.openstack_version }} + enable_plugin manila https://github.com/openstack/manila ${{ matrix.openstack_version }} + + [[post-config|/etc/nova/nova.conf]] + [filter_scheduler] + enabled_filters = ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,ServerGroupAffinityFilter,SameHostFilter,DifferentHostFilter,SimpleCIDRAffinityFilter,JsonFilter - name: Deploy a Kind Cluster - uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab + uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # tag=v1.14.0 with: cluster_name: orc @@ -66,7 +75,7 @@ jobs: - name: Upload logs artifacts on failure if: failure() - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # tag=v7.0.1 with: name: e2e-${{ matrix.name }}-${{ github.run_id }} path: /tmp/artifacts/* diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index d4cea7346..e90a8df12 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -13,8 +13,10 @@ jobs: ensure: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.1 - - uses: micnncim/action-label-syncer@v1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: false + - uses: micnncim/action-label-syncer@3abd5ab72fda571e69fffd97bd4e0033dd5f495c # tag=v1.3.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/generate.yaml b/.github/workflows/generate.yaml index c87b2dbfb..d6ab64616 100644 --- a/.github/workflows/generate.yaml +++ b/.github/workflows/generate.yaml @@ -13,8 +13,16 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: false - run: | make generate git diff --exit-code + + - run: sudo apt-get install -y libgpgme-dev + + - run: | + make generate-bundle + git diff --exit-code diff --git a/.github/workflows/go-lint.yaml b/.github/workflows/go-lint.yaml index d8673921e..cb1bdca4a 100644 --- a/.github/workflows/go-lint.yaml +++ b/.github/workflows/go-lint.yaml @@ -13,14 +13,16 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: false - name: Calculate go version id: vars run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # tag=v6.1.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # tag=v7.0.0 with: go-version: ${{ steps.vars.outputs.go_version }} diff --git a/.github/workflows/label-issue.yaml b/.github/workflows/label-issue.yaml index 45ab4cbe3..831c6a8a4 100644 --- a/.github/workflows/label-issue.yaml +++ b/.github/workflows/label-issue.yaml @@ -7,7 +7,7 @@ on: jobs: clear_needinfo: name: Clear needinfo - if: ${{ github.event.issue.user.login }} == ${{ github.event.comment.user.login }} + if: github.event.issue.user.login == github.event.comment.user.login runs-on: ubuntu-latest permissions: issues: write diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 975d02ad2..86a109eb7 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -1,92 +1,84 @@ name: Label PR on: + # zizmor: ignore[dangerous-triggers] edits job only runs actions/labeler, no code checkout pull_request_target: types: - opened - synchronize - reopened -permissions: - contents: read - pull-requests: write + # zizmor: ignore[dangerous-triggers] semver-label job never checks out or executes untrusted code + workflow_run: + workflows: ["Semver analysis"] + types: + - completed + +permissions: {} jobs: - semver: + semver-label: + if: github.event_name == 'workflow_run' runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write steps: - - uses: actions/checkout@v6.0.1 + - name: Download semver results + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # tag=v8.0.1 with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha }} - token: ${{ secrets.GITHUB_TOKEN }} + name: semver-results + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Read PR number + id: pr + run: echo "number=$(cat pr-number)" >> $GITHUB_OUTPUT - - name: Rebase the PR against origin/github.base_ref to ensure actual API compatibility + - name: Report failure + if: github.event.workflow_run.conclusion == 'failure' run: | - git config --global user.email "localrebase@k-orc.cloud" - git config --global user.name "Local rebase" - git rebase -i origin/${{ github.base_ref }} + gh pr edit "$NUMBER" --remove-label "semver:major,semver:minor,semver:patch" + gh issue comment "$NUMBER" --body "$BODY" env: - GIT_SEQUENCE_EDITOR: '/usr/bin/true' - - - name: Calculate go version - id: vars - run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT - - - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # tag=v6.1.0 - with: - go-version: ${{ steps.vars.outputs.go_version }} - - - name: Checking Go API Compatibility - id: go-apidiff - # if semver=major, this will return RC=1, so let's ignore the failure so label - # can be set later. We check for actual errors in the next step. - continue-on-error: true - uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ steps.pr.outputs.number }} + BODY: > + Failed to assess the semver bump. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) for details. - # go-apidiff returns RC=1 when semver=major, which makes the workflow to return - # a failure. Instead let's just return a failure if go-apidiff failed to run. - - name: Return an error if Go API Compatibility couldn't be verified - if: steps.go-apidiff.outcome != 'success' && steps.go-apidiff.outputs.semver-type != 'major' - run: exit 1 + - name: Read semver type + if: github.event.workflow_run.conclusion == 'success' + id: semver + run: echo "type=$(cat semver-type)" >> $GITHUB_OUTPUT - name: Add label semver:patch - if: steps.go-apidiff.outputs.semver-type == 'patch' + if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'patch' run: gh pr edit "$NUMBER" --add-label "semver:patch" --remove-label "semver:major,semver:minor" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} + NUMBER: ${{ steps.pr.outputs.number }} - name: Add label semver:minor - if: steps.go-apidiff.outputs.semver-type == 'minor' + if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'minor' run: gh pr edit "$NUMBER" --add-label "semver:minor" --remove-label "semver:major,semver:patch" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} + NUMBER: ${{ steps.pr.outputs.number }} - name: Add label semver:major - if: steps.go-apidiff.outputs.semver-type == 'major' + if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'major' run: gh pr edit "$NUMBER" --add-label "semver:major" --remove-label "semver:minor,semver:patch" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} - - - name: Report failure - if: failure() - run: | - gh pr edit "$NUMBER" --remove-label "semver:major,semver:minor,semver:patch" - gh issue comment "$NUMBER" --body "$BODY" - exit 1 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} - BODY: > - Failed to assess the semver bump. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. + NUMBER: ${{ steps.pr.outputs.number }} edits: + if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write steps: - - uses: actions/labeler@v6 + - uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # tag=v7.0.0 diff --git a/.github/workflows/pr-dependabot.yaml b/.github/workflows/pr-dependabot.yaml index 35ca7c99c..fd4428821 100644 --- a/.github/workflows/pr-dependabot.yaml +++ b/.github/workflows/pr-dependabot.yaml @@ -19,15 +19,17 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code into the Go module directory - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v4.2.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: true # zizmor: ignore[artipacked] EndBug/add-and-commit needs git credentials to push - name: Calculate go version id: vars run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # tag=v6.1.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # tag=v7.0.0 with: go-version: ${{ steps.vars.outputs.go_version }} - - uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # tag=v5.0.1 + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # tag=v6.1.0 name: Restore go cache with: path: | @@ -40,7 +42,7 @@ jobs: run: make modules - name: Update generated code run: make generate - - uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # tag=v9.1.4 + - uses: EndBug/add-and-commit@290ea2c423ad77ca9c62ae0f5b224379612c0321 # tag=v10.0.0 name: Commit changes with: author_name: dependabot[bot] diff --git a/.github/workflows/release_image.yaml b/.github/workflows/release_image.yaml index 98c855442..c43cb22ed 100644 --- a/.github/workflows/release_image.yaml +++ b/.github/workflows/release_image.yaml @@ -17,19 +17,20 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 with: # Required for git describe to generate correct output for populating # build variables fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # tag=v4.2.0 - name: Install build dependencies run: sudo apt-get install -y libgpgme-dev - run: | - docker login -u="${{ secrets.QUAY_USERNAME }}" -p="${{ secrets.QUAY_TOKEN }}" quay.io + docker login -u="${{ secrets.QUAY_USERNAME }}" -p="${{ secrets.QUAY_TOKEN }}" quay.io # zizmor: ignore[secrets-outside-env] make docker-buildx IMG=${{ env.image_tag }} make build-bundle-image BUNDLE_IMG=${{ env.bundle_image_tag }} make docker-push IMG=${{ env.bundle_image_tag }} diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml new file mode 100644 index 000000000..64868723f --- /dev/null +++ b/.github/workflows/semver.yaml @@ -0,0 +1,68 @@ +name: Semver analysis +on: + pull_request: + types: + - opened + - synchronize + - reopened + +permissions: + contents: read + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + + - name: Rebase the PR against base ref to ensure actual API compatibility + run: | + git config --global user.email "localrebase@k-orc.cloud" + git config --global user.name "Local rebase" + git rebase -i origin/$BASE_REF + env: + GIT_SEQUENCE_EDITOR: '/usr/bin/true' + BASE_REF: ${{ github.base_ref }} + + - name: Calculate go version + id: vars + run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT + + - name: Set up Go + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # tag=v7.0.0 + with: + go-version: ${{ steps.vars.outputs.go_version }} + + - name: Checking Go API Compatibility + id: go-apidiff + # if semver=major, this will return RC=1, so let's ignore the failure so label + # can be set later. We check for actual errors in the next step. + continue-on-error: true + uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 # tag=v0.8.3 + + # go-apidiff returns RC=1 when semver=major, which makes the workflow to return + # a failure. Instead let's just return a failure if go-apidiff failed to run. + - name: Return an error if Go API Compatibility couldn't be verified + if: steps.go-apidiff.outcome != 'success' && steps.go-apidiff.outputs.semver-type != 'major' + run: exit 1 + + - name: Save semver result + if: always() + run: | + mkdir -p semver-results + echo "$SEMVER_TYPE" > semver-results/semver-type + echo "$PR_NUMBER" > semver-results/pr-number + env: + SEMVER_TYPE: ${{ steps.go-apidiff.outputs.semver-type }} + PR_NUMBER: ${{ github.event.pull_request.number }} + + - name: Upload semver results + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # tag=v7.0.1 + with: + name: semver-results + path: semver-results/ diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 1b8bf4604..229302816 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -17,14 +17,16 @@ jobs: - '1' steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: false - name: Calculate go version id: vars run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # tag=v6.1.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # tag=v7.0.0 with: go-version: ${{ steps.vars.outputs.go_version }} diff --git a/.github/workflows/website.yaml b/.github/workflows/website.yaml index 5ae350748..2400af0d8 100644 --- a/.github/workflows/website.yaml +++ b/.github/workflows/website.yaml @@ -17,7 +17,9 @@ jobs: name: Publish to Cloudflare Pages steps: - name: Checkout - uses: actions/checkout@v6.0.1 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: false - name: Pip install run: pip install -Ur website/requirements.txt @@ -26,10 +28,10 @@ jobs: run: mkdocs build --verbose --strict --config-file website/mkdocs.yml --site-dir rendered - name: Publish to Cloudflare Pages - uses: cloudflare/pages-action@v1 + uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca # tag=v1.5.0 with: - apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} # zizmor: ignore[secrets-outside-env] + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} # zizmor: ignore[secrets-outside-env] projectName: k-orc directory: website/rendered gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/weekly-security-scan.yaml b/.github/workflows/weekly-security-scan.yaml index ccca71f45..409580f9f 100644 --- a/.github/workflows/weekly-security-scan.yaml +++ b/.github/workflows/weekly-security-scan.yaml @@ -13,19 +13,20 @@ jobs: strategy: fail-fast: false matrix: - branch: [main, release-1.0] + branch: [main, release-2.0] name: Trivy runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # tag=v4.2.2 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 with: ref: ${{ matrix.branch }} + persist-credentials: false - name: Calculate go version id: vars run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT - name: Set up Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # tag=v6.1.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # tag=v7.0.0 with: go-version: ${{ steps.vars.outputs.go_version }} - name: Run verify security target diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml new file mode 100644 index 000000000..ec149e4d5 --- /dev/null +++ b/.github/workflows/zizmor.yaml @@ -0,0 +1,28 @@ +name: zizmor + +on: + push: + branches: + - main + paths: + - '.github/**' + pull_request: + paths: + - '.github/**' + +permissions: {} + +jobs: + zizmor: + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@6599ee8b7a49aef6a770f63d261d214911a7ce02 # tag=v0.6.0 diff --git a/.golangci.yml b/.golangci.yml index 3301a5c65..cf5891f9c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -34,10 +34,14 @@ linters: settings: linters: disable: + # NOTE: conflicts with the lack of validation in the Status structs + - arrayofstruct + # NOTE: The following checks are currently failing - optionalfields enable: - commentstart - conditions + - defaults - duplicatemarkers - integers - jsontags @@ -48,6 +52,7 @@ linters: - nodurations - nofloats - nomaps + - nonpointerstructs - nonullable - notimestamp - nophase @@ -57,16 +62,20 @@ linters: - statusoptional - statussubresource - uniquemarkers + - noopenstackidref lintersConfig: conditions: isFirstField: Warn usePatchStrategy: Ignore useProtobuf: Forbid + defaults: + # Let's use `+kubebuilder:default` until elastic/crd-ref-docs supports `+default` + preferredDefaultMarker: "kubebuilder:default" requiredfields: omitempty: policy: Ignore exclusions: - generated: lax + generated: disable rules: - linters: - lll @@ -75,13 +84,25 @@ linters: - dupl - lll path: internal/* + - linters: + - dupl + path: test/* + - linters: + - dupl + - goimports + - unparam + path: zz_generated - linters: - kubeapilinter - path-except: api/* + path-except: ^api/* paths: - third_party$ - builtin$ - examples$ + - applyconfiguration/* + - clientset/* + - informers/* + - listers/* formatters: enable: - gofmt @@ -92,3 +113,5 @@ formatters: - third_party$ - builtin$ - examples$ +issues: + exclude-generated: disable diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..e91759dda --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,412 @@ +# OpenStack Resource Controller (ORC) - Development Guide + +This document provides instructions for AI agents to develop controllers in the ORC project. + +## Project Overview + +ORC is a Kubernetes operator that manages OpenStack resources declaratively. Each OpenStack resource (Flavor, Server, Network, etc.) has a corresponding Kubernetes Custom Resource and controller. + +**Key Principle**: ORC objects only reference other ORC objects, never OpenStack resources directly. OpenStack resource IDs appear only in status fields. + +## Project Structure + +``` +openstack-resource-controller/ +├── api/v1alpha1/ # CRD type definitions (*_types.go) +├── internal/ +│ ├── controllers/ # Controller implementations +│ │ └── / # Each controller in its own package +│ │ ├── controller.go # Setup, dependencies, SetupWithManager +│ │ ├── actuator.go # OpenStack CRUD operations +│ │ ├── status.go # Status writer implementation +│ │ ├── zz_generated.*.go # Generated code (DO NOT EDIT) +│ │ └── tests/ # KUTTL E2E tests +│ ├── logging/ # Log level constants +│ ├── osclients/ # OpenStack API client wrappers +│ ├── scope/ # Cloud credentials & client factory +│ └── util/ +│ ├── applyconfigs/ # SSA apply config helpers +│ ├── credentials/ # Credential watch & dependency setup +│ ├── dependency/ # Dependency framework +│ ├── errors/ # Error classification (Terminal, IsRetryable) +│ ├── finalizers/ # Finalizer helpers +│ ├── result/ # Result helpers +│ ├── strings/ # Finalizer/field-owner name generation +│ └── tags/ # Tag reconciliation utilities +├── cmd/ +│ ├── manager/ # Main entry point +│ ├── models-schema/ # OpenAPI schema generation +│ ├── resource-generator/ # Code generation +│ └── scaffold-controller/ # New controller scaffolding +└── website/docs/development/ # Detailed documentation +``` + +## Architecture + +### Generic Reconciler Framework + +All controllers use a generic reconciler that handles the reconciliation loop. Controllers implement interfaces: + +- **CreateResourceActuator**: Create and import operations +- **DeleteResourceActuator**: Delete operations +- **ReconcileResourceActuator**: Post-creation updates (optional) +- **ResourceStatusWriter**: Status and condition management + +### Key Interfaces + +Controllers implement these methods (see `internal/controllers/servergroup/` for a simple example): + +```go +// Required by all actuators +GetResourceID(osResource) string +GetOSResourceByID(ctx, id) (*osResource, ReconcileStatus) +ListOSResourcesForAdoption(ctx, obj) (iterator, bool) + +// For creation/import +ListOSResourcesForImport(ctx, obj, filter) (iterator, ReconcileStatus) +CreateResource(ctx, orcObject) (*osResource, ReconcileStatus) + +// For deletion +DeleteResource(ctx, orcObject, osResource) ReconcileStatus + +// Optional - for updates after creation +GetResourceReconcilers(ctx, obj, osResource, controller) ([]ResourceReconciler, ReconcileStatus) +``` + +### Two Critical Conditions + +Every ORC object has these conditions: + +1. **Progressing** + - `True`: Spec doesn't match status; controller expects more reconciles + - `False`: Either available OR terminal error (no more reconciles until spec changes) + +2. **Available** + - `True`: Resource is ready for use + - Determined by `ResourceStatusWriter.ResourceAvailableStatus()` + +### ReconcileStatus Pattern + +Methods return `ReconcileStatus` instead of `error`: + +`ReconcileStatus` is a type alias for a pointer (`type ReconcileStatus = *reconcileStatus`). `nil` is a valid value meaning "success, no reschedule", and all methods are safe to call on a nil receiver. + +```go +nil // Success, no reschedule +progress.WrapError(err) // Wrap error for handling +reconcileStatus.WithRequeue(5*time.Second) // Schedule reconcile after delay +reconcileStatus.WithProgressMessage("...") // Add progress message +progress.NeedsRefresh() // Immediate re-reconcile to refresh status after mutation +progress.WaitingOnOpenStack(progress.WaitingOnReady, 15*time.Second) // Poll for OpenStack state change +progress.WaitingOnObject("Network", name, progress.WaitingOnCreation) // Wait for a k8s object +reconcileStatus.WithReconcileStatus(other) // Merge two ReconcileStatuses +``` + +### Error Classification + +- **Transient errors** (5xx, API unavailable): Default handling with exponential backoff +- **Non-recoverable errors** (409 Conflict, non-HTTP gophercloud errors): Wrap with `orcerrors.Terminal()` - no retry + +```go +// Non-recoverable error example +if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, + "invalid configuration: "+err.Error(), err) + } + return nil, progress.WrapError(err) +} +``` + +## Dependencies + +Dependencies are core to ORC - they ensure resources are created in order. + +### Types of Dependencies + +1. **Normal Dependency**: Wait for object to exist and be available +2. **Deletion Guard Dependency**: Normal + prevents deletion of dependency while in use + +### Declaring Dependencies (in controller.go) + +```go +var projectDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.SecurityGroupList, *orcv1alpha1.Project]( + "spec.resource.projectRef", // Field path for indexing + func(sg *orcv1alpha1.SecurityGroup) []string { + if sg.Spec.Resource != nil && sg.Spec.Resource.ProjectRef != nil { + return []string{string(*sg.Spec.Resource.ProjectRef)} + } + return nil + }, + finalizer, externalObjectFieldOwner, +) +``` + +### Using Dependencies (in actuator.go) + +```go +project, reconcileStatus := projectDependency.GetDependency( + ctx, actuator.k8sClient, orcObject, + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, +) +if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus +} +// project is now guaranteed available +projectID := ptr.Deref(project.Status.ID, "") +``` + +### Lightweight Dependency Lookup (FetchDependency) + +For one-off lookups that don't need finalizers (e.g., resolving refs in `ListOSResourcesForAdoption` or import filters), use `dependency.FetchDependency` instead of a declared dependency: + +```go +import "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + +project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, +) +reconcileStatus = reconcileStatus.WithReconcileStatus(rs) +``` + +### Credentials Dependency (generated) + +Every controller has a `credentialsDependency` auto-generated in `zz_generated.controller.go`. It is a `DeletionGuardDependency` on `corev1.Secret` that ensures the cloud credentials secret exists and carries the controller's finalizer. It is checked in `newActuator()` before creating an OpenStack client: + +```go +_, reconcileStatus := credentialsDependency.GetDependencies( + ctx, controller.GetK8sClient(), orcObject, + func(*corev1.Secret) bool { return true }, +) +if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return myActuator{}, reconcileStatus +} +``` + +The credential watch is registered in `SetupWithManager` via `credentials.AddCredentialsWatch()`. + +## Common Patterns + +### Resource Name Helper (generated) + +`getResourceName` is auto-generated in `zz_generated.adapter.go` — do not write it manually. It returns `spec.resource.name` if set, otherwise falls back to the ORC object's Kubernetes name: + +```go +// In zz_generated.adapter.go (DO NOT EDIT) +func getResourceName(orcObject orcObjectPT) string { + if orcObject.Spec.Resource.Name != nil { + return string(*orcObject.Spec.Resource.Name) + } + return orcObject.Name +} +``` + +### Type Aliases (top of actuator.go) + +```go +type ( + osResourceT = flavors.Flavor + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) +``` + +### Interface Assertions + +```go +var _ createResourceActuator = flavorActuator{} +var _ deleteResourceActuator = flavorActuator{} +``` + +### Actuator Factory (newActuator) + +Every controller defines a `newActuator()` function that resolves credentials, creates the OpenStack client scope, and returns the actuator. This is called by the `helperFactory` methods `NewCreateActuator` and `NewDeleteActuator`: + +```go +func newActuator(ctx context.Context, orcObject *orcv1alpha1.Flavor, controller generic.ResourceController) (flavorActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies( + ctx, controller.GetK8sClient(), orcObject, + func(*corev1.Secret) bool { return true }, + ) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return flavorActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject( + ctx, controller.GetK8sClient(), log, orcObject, + ) + if err != nil { + return flavorActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewComputeClient() // or NewNetworkClient, etc. + if err != nil { + return flavorActuator{}, progress.WrapError(err) + } + + return flavorActuator{osClient: osClient}, nil +} +``` + +### Tag Reconciliation (Neutron resources) + +Neutron resources use a separate tags API instead of the resource's Update API. The `internal/util/tags` package provides a reusable reconciler: + +```go +import "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" + +func (actuator myActuator) GetResourceReconcilers(...) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + tags.ReconcileTags[orcObjectPT, osResourceT]( + orcObject.Spec.Resource.Tags, + osResource.Tags, + tags.NewNeutronTagReplacer(actuator.osClient, "security-groups", osResource.ID), + ), + actuator.updateRules, + }, nil +} +``` + +`ReconcileTags` computes the diff between desired and observed tags and replaces them atomically. For resources whose tags are set via the standard Update API (e.g., block storage), use a `handleTagsUpdate()` helper in `updateResource` instead. + +### Pointer Handling + +```go +import "k8s.io/utils/ptr" + +ptr.Deref(optionalPtr, defaultValue) // Dereference with default +ptr.To(value) // Create pointer +``` + +## API Types Structure + +### ResourceSpec (creation parameters) + +```go +// Most resources have a mix of immutable and mutable fields. +// Immutability is typically applied per-field, not on the whole struct. +type ServerResourceSpec struct { + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // +required + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="imageRef is immutable" + ImageRef KubernetesNameRef `json:"imageRef,omitempty"` + + // tags is mutable (no immutability validation) + // +optional + Tags []ServerTag `json:"tags,omitempty"` +} + +// Some resources are fully immutable (rare - e.g., ServerGroup) +// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ServerGroupResourceSpec is immutable" +type ServerGroupResourceSpec struct { + // ... +} +``` + +### Filter (import parameters) + +```go +// +kubebuilder:validation:MinProperties:=1 +type FlavorFilter struct { + Name *OpenStackName `json:"name,omitempty"` + RAM *int32 `json:"ram,omitempty"` +} +``` + +### ResourceStatus (observed state) + +```go +type FlavorResourceStatus struct { + Name string `json:"name,omitempty"` + RAM *int32 `json:"ram,omitempty"` +} +``` + +## Logging Levels + +```go +import "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + +log.V(logging.Status).Info("...") // Always shown: startup, shutdown +log.V(logging.Info).Info("...") // Default: creation/deletion, reconcile complete +log.V(logging.Verbose).Info("...") // Admin: fires every reconcile +log.V(logging.Debug).Info("...") // Development: detailed debugging +``` + +## Key Make Targets + +```bash +make generate # Generate all code (run after API type changes) +make build # Build manager binary +make lint # Run linters +make test # Run unit tests +make test-e2e # Run KUTTL E2E tests (requires E2E_OSCLOUDS) +make fmt # Format code +``` + +## Reconciler Naming Conventions + +`GetResourceReconcilers` returns a list of reconciler functions. There are two types: + +1. **`updateResource`**: Handles general mutable field updates via the resource's Update API. Uses `handleXXXUpdate()` helpers to build an `UpdateOpts` struct, then makes a single API call. Returns a terminal error when `spec.resource` is nil. Examples: securitygroup, volumetype, trunk, router. + +2. **Single-concern reconcilers**: Handle a specific aspect of the resource using a separate API (not the resource's Update API). Named with a descriptive verb+noun (e.g., `reconcileExtraSpecs`, `reconcileSubports`, `reconcilePassword`, `updateRules`). Return `nil` (not a terminal error) when `spec.resource` is nil. May make multiple API calls within a single reconciler. + +```go +// updateResource pattern - general mutable fields via Update API +func (actuator myActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + resource := obj.Spec.Resource + if resource == nil { + // Terminal error: updateResource is only registered for managed resources + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + // ... build UpdateOpts, make single Update API call +} + +// Single-concern reconciler pattern - separate API +func (actuator myActuator) reconcileExtraSpecs(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + resource := obj.Spec.Resource + if resource == nil { + return nil // Not a terminal error + } + // ... compute diff, make API calls (creates, deletes, etc.) +} +``` + +Both types are registered in `GetResourceReconcilers`: +```go +func (actuator myActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller generic.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.updateResource, // general field updates + actuator.reconcileExtraSpecs, // single-concern reconciler + }, nil +} +``` + +## Reference Controllers + +- **Simple**: `internal/controllers/servergroup/` - No dependencies, fully immutable +- **Single-concern reconciler**: `internal/controllers/flavor/` - No dependencies, immutable except extra specs (`reconcileExtraSpecs`) +- **With dependencies**: `internal/controllers/securitygroup/` - Project dependency, rules reconciliation +- **Multiple reconcilers**: `internal/controllers/trunk/` - `updateResource` + `reconcileSubports` + tags +- **Complex**: `internal/controllers/server/` - Multiple dependencies, many reconcilers + +## Documentation + +Detailed documentation in `website/docs/development/`: +- `scaffolding.md` - Creating new controllers +- `controller-implementation.md` - Progressing condition, ReconcileStatus +- `interfaces.md` - Detailed interface descriptions +- `coding-standards.md` - Code style and conventions +- `writing-tests.md` - Testing patterns diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 000000000..47dc3e3d8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Makefile b/Makefile index 37b4913a1..ea8d927de 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ IMG ?= controller:latest BUNDLE_IMG ?= bundle:latest # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.29.0 -TRIVY_VERSION = 0.49.1 -GO_VERSION ?= 1.24.11 +TRIVY_VERSION = 0.69.3 +GO_VERSION ?= 1.25.11 # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) @@ -139,7 +139,7 @@ lint: golangci-kal ## Run golangci-kal linter $(GOLANGCI_KAL) run .PHONY: lint-fix -lint-fix: golangci-kal ## Run golangci-lint linter and perform fixes +lint-fix: golangci-kal ## Run golangci-kal linter and perform fixes $(GOLANGCI_KAL) run --fix ##@ Build @@ -311,15 +311,14 @@ GOVULNCHECK = $(LOCALBIN)/govulncheck OPERATOR_SDK = $(LOCALBIN)/operator-sdk ## Tool Versions -KUSTOMIZE_VERSION ?= v5.6.0 -CONTROLLER_TOOLS_VERSION ?= v0.17.1 -ENVTEST_VERSION ?= release-0.22 -GOLANGCI_LINT_VERSION ?= v2.7.2 -KAL_VERSION ?= v0.0.0-20250924094418-502783c08f9d -MOCKGEN_VERSION ?= v0.5.0 -KUTTL_VERSION ?= v0.23.0 +KUSTOMIZE_VERSION ?= v5.8.1 +CONTROLLER_TOOLS_VERSION ?= v0.20.1 +ENVTEST_VERSION ?= release-0.23 +GOLANGCI_LINT_VERSION ?= v2.11.4 +MOCKGEN_VERSION ?= v0.6.0 +KUTTL_VERSION ?= v0.26.0 GOVULNCHECK_VERSION ?= v1.1.4 -OPERATOR_SDK_VERSION ?= v1.41.1 +OPERATOR_SDK_VERSION ?= v1.42.2 .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. @@ -346,8 +345,8 @@ version: $(GOLANGCI_LINT_VERSION) name: golangci-kube-api-linter destination: $(LOCALBIN) plugins: -- module: 'sigs.k8s.io/kube-api-linter' - version: $(KAL_VERSION) +- module: 'github.com/k-orc/openstack-resource-controller/v2/tools/orc-api-linter' + path: ./tools/orc-api-linter endef export custom-gcl @@ -357,6 +356,7 @@ CUSTOM_GCL_FILE ?= $(shell pwd)/.custom-gcl.yml golangci-kal: $(GOLANGCI_KAL) $(GOLANGCI_KAL): $(LOCALBIN) $(GOLANGCI_LINT) $(file >$(CUSTOM_GCL_FILE),$(custom-gcl)) + cd tools/orc-api-linter && go mod tidy $(GOLANGCI_LINT) custom .PHONY: mockgen diff --git a/PROJECT b/PROJECT index 8d6e2c12d..357849779 100644 --- a/PROJECT +++ b/PROJECT @@ -8,6 +8,22 @@ layout: projectName: orc repo: github.com/k-orc/openstack-resource-controller resources: +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: AddressScope + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: ApplicationCredential + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 namespaced: true @@ -16,6 +32,14 @@ resources: kind: Domain path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: Endpoint + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 namespaced: true @@ -88,6 +112,14 @@ resources: kind: Role path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: RoleAssignment + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 namespaced: true @@ -136,6 +168,14 @@ resources: kind: Service path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: ShareNetwork + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 namespaced: true @@ -144,6 +184,22 @@ resources: kind: Subnet path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: Trunk + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: User + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 namespaced: true diff --git a/README.md b/README.md index 0eb8b6a23..a5663e5fd 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,13 @@ ORC is based on [Gophercloud][gophercloud], the OpenStack Go SDK. ## Maturity -While we currently cover a limited subset of OpenStack resources, we focus on -making existing controllers as correct and predictable as possible. We -encourage you to contribute, file issues, and help improve the project as we -continue to work on it! +ORC is deployed and used in production environments and is notably a dependency +of Cluster API's [OpenStack provider](https://github.com/kubernetes-sigs/cluster-api-provider-openstack). + +The Kubernetes API is currently `v1alpha1`. The core API patterns are stable and +we do not anticipate major structural changes, but the API is still evolving as +we add new controllers and features. We do not have a timeline for graduation to +`v1beta1`. ORC versioning follows [semver](https://semver.org/spec/v2.0.0.html): there will be no breaking changes within a major release. @@ -34,6 +37,9 @@ We welcome contributions of all kinds! Whether you’re fixing bugs, adding new * Make your changes and test thoroughly. * Submit a pull request with a clear description of your changes. +For significant new features or architectural changes, please review our +[enhancement proposal process](enhancements/README.md) before starting work. + If you're unsure where to start, check out the [open issues](https://github.com/k-orc/openstack-resource-controller/issues) and feel free to ask questions or propose ideas! @@ -65,9 +71,12 @@ kubectl delete -f $ORC_RELEASE ## Supported OpenStack resources -| **controller** | **1.x** | **2.x** | **main** | +| **controller** | **1.x (EOL)** | **2.x** | **main** | |:---------------------------:|:-------:|:-------:|:--------:| +| addressscope | | ✔ | ✔ | +| application credential | | ◐ | ◐ | | domain | | ✔ | ✔ | +| endpoint | | ◐ | ◐ | | flavor | | ✔ | ✔ | | floating ip | | ◐ | ◐ | | group | | ✔ | ✔ | @@ -82,19 +91,21 @@ kubectl delete -f $ORC_RELEASE | server | | ◐ | ◐ | | server group | | ✔ | ✔ | | service | | ✔ | ✔ | +| share network | | | ◐ | | subnet | | ◐ | ◐ | +| trunk | | ✔ | ✔ | +| user | | ◐ | ◐ | | volume | | ◐ | ◐ | | volume type | | ◐ | ◐ | - ✔: mostly implemented ◐: partially implemented ## License -Copyright 2024. +Copyright 2026. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/SECURITY.md b/SECURITY.md index 936f73a2d..e8a9e7210 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ | Version | Supported | | ------- | ------------------ | | < 1.0 | :x: | -| 1.x | :white_check_mark: | +| 1.x | :x: | | 2.x | :white_check_mark: | ## Reporting a Vulnerability diff --git a/api/v1alpha1/addressscope_types.go b/api/v1alpha1/addressscope_types.go new file mode 100644 index 000000000..8a28e4585 --- /dev/null +++ b/api/v1alpha1/addressscope_types.go @@ -0,0 +1,88 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +// AddressScopeResourceSpec contains the desired state of the resource. +type AddressScopeResourceSpec struct { + // name will be the name of the created resource. If not specified, the + // name of the ORC object will be used. + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // projectRef is a reference to the ORC Project which this resource is associated with. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="projectRef is immutable" + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` + + // ipVersion is the IP protocol version. + // +required + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ipVersion is immutable" + IPVersion IPVersion `json:"ipVersion"` + + // shared indicates whether this resource is shared across all + // projects or not. By default, only admin users can change set + // this value. We can't unshared a shared address scope; Neutron + // enforces this. + // +optional + // +kubebuilder:validation:XValidation:rule="!(oldSelf && !self)",message="shared address scope can't be unshared" + Shared *bool `json:"shared,omitempty"` +} + +// AddressScopeFilter defines an existing resource by its properties +// +kubebuilder:validation:MinProperties:=1 +type AddressScopeFilter struct { + // name of the existing resource + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // projectRef is a reference to the ORC Project which this resource is associated with. + // +optional + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` + + // ipVersion is the IP protocol version. + // +optional + IPVersion IPVersion `json:"ipVersion,omitempty"` + + // shared indicates whether this resource is shared across all + // projects or not. By default, only admin users can change set + // this value. + // +optional + Shared *bool `json:"shared,omitempty"` +} + +// AddressScopeResourceStatus represents the observed state of the resource. +type AddressScopeResourceStatus struct { + // name is a Human-readable name for the resource. Might not be unique. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Name string `json:"name,omitempty"` + + // projectID is the ID of the Project to which the resource is associated. + // +kubebuilder:validation:MaxLength=1024 + // +optional + ProjectID string `json:"projectID,omitempty"` + + // ipVersion is the IP protocol version. + // +optional + IPVersion int32 `json:"ipVersion,omitempty"` + + // shared indicates whether this resource is shared across all + // projects or not. By default, only admin users can change set + // this value. + // +optional + Shared *bool `json:"shared,omitempty"` +} diff --git a/api/v1alpha1/applicationcredential_types.go b/api/v1alpha1/applicationcredential_types.go new file mode 100644 index 000000000..bcb11a3dd --- /dev/null +++ b/api/v1alpha1/applicationcredential_types.go @@ -0,0 +1,190 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +kubebuilder:validation:Enum:=CONNECT;DELETE;GET;HEAD;OPTIONS;PATCH;POST;PUT;TRACE +type HTTPMethod string + +const ( + HTTPMethodCONNECT HTTPMethod = "CONNECT" + HTTPMethodDELETE HTTPMethod = "DELETE" + HTTPMethodGET HTTPMethod = "GET" + HTTPMethodHEAD HTTPMethod = "HEAD" + HTTPMethodOPTIONS HTTPMethod = "OPTIONS" + HTTPMethodPATCH HTTPMethod = "PATCH" + HTTPMethodPOST HTTPMethod = "POST" + HTTPMethodPUT HTTPMethod = "PUT" + HTTPMethodTRACE HTTPMethod = "TRACE" +) + +// ApplicationCredentialAccessRule defines an access rule +// +kubebuilder:validation:MinProperties:=1 +type ApplicationCredentialAccessRule struct { + // path that the application credential is permitted to access + // +kubebuilder:validation:MaxLength=1024 + // +optional + Path *string `json:"path,omitempty"` + + // method that the application credential is permitted to use for a given API endpoint + // +optional + Method *HTTPMethod `json:"method,omitempty"` + + // serviceRef identifier for the service that the application credential is permitted to access + // +optional + ServiceRef *KubernetesNameRef `json:"serviceRef,omitempty"` +} + +// ApplicationCredentialResourceSpec contains the desired state of the resource. +// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ApplicationCredentialResourceSpec is immutable" +type ApplicationCredentialResourceSpec struct { + // name will be the name of the created resource. If not specified, the + // name of the ORC object will be used. + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + Description *string `json:"description,omitempty"` + + // userRef is a reference to the ORC User which this resource is associated with. + // Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. + // +required + UserRef KubernetesNameRef `json:"userRef,omitempty"` + + // unrestricted is a flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts + // +optional + Unrestricted *bool `json:"unrestricted,omitempty"` + + // secretRef is a reference to a Secret containing the application credential secret + // +required + SecretRef KubernetesNameRef `json:"secretRef,omitempty"` + + // roleRefs may only contain roles that the user has assigned on the project. If not provided, the roles assigned to the application credential will be the same as the roles in the current token. + // +kubebuilder:validation:MaxItems:=256 + // +listType=atomic + // +optional + RoleRefs []KubernetesNameRef `json:"roleRefs,omitempty"` + + // accessRules is a list of fine grained access control rules + // +kubebuilder:validation:MaxItems:=256 + // +listType=atomic + // +optional + AccessRules []ApplicationCredentialAccessRule `json:"accessRules,omitempty"` + + // expiresAt is the time of expiration for the application credential. If unset, the application credential does not expire. + // +optional + ExpiresAt *metav1.Time `json:"expiresAt,omitempty"` +} + +// ApplicationCredentialFilter defines an existing resource by its properties +// +kubebuilder:validation:MinProperties:=2 +type ApplicationCredentialFilter struct { + // userRef is a reference to the ORC User which this resource is associated with. + // Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. + // +required + UserRef KubernetesNameRef `json:"userRef,omitempty"` + + // name of the existing resource + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description of the existing resource + // +kubebuilder:validation:MaxLength:=1024 + // +optional + Description *string `json:"description,omitempty"` +} + +type ApplicationCredentialRoleStatus struct { + // name of an existing role + // +kubebuilder:validation:MaxLength:=1024 + // +optional + Name *string `json:"name,omitempty"` + + // id is the ID of a role + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // domainID of the domain of this role + // +kubebuilder:validation:MaxLength:=1024 + // +optional + DomainID *string `json:"domainID,omitempty"` +} + +type ApplicationCredentialAccessRuleStatus struct { + // id is the ID of this access rule + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // path that the application credential is permitted to access + // +kubebuilder:validation:MaxLength:=1024 + // +optional + Path *string `json:"path,omitempty"` + + // method that the application credential is permitted to use for a given API endpoint + // +kubebuilder:validation:MaxLength=32 + // +optional + Method *string `json:"method,omitempty"` + + // service type identifier for the service that the application credential is permitted to access + // +kubebuilder:validation:MaxLength:=1024 + // +optional + Service *string `json:"service,omitempty"` +} + +// ApplicationCredentialResourceStatus represents the observed state of the resource. +type ApplicationCredentialResourceStatus struct { + // name is a Human-readable name for the resource. Might not be unique. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Name string `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Description string `json:"description,omitempty"` + + // unrestricted is a flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts + // +optional + Unrestricted bool `json:"unrestricted,omitempty"` + + // projectID of the project the application credential was created for and that authentication requests using this application credential will be scoped to. + // +kubebuilder:validation:MaxLength=1024 + // +optional + ProjectID string `json:"projectID,omitempty"` + + // roles is a list of role objects may only contain roles that the user has assigned on the project + // +kubebuilder:validation:MaxItems:=64 + // +listType=atomic + // +optional + Roles []ApplicationCredentialRoleStatus `json:"roles"` + + // expiresAt is the time of expiration for the application credential. If unset, the application credential does not expire. + // +optional + ExpiresAt *metav1.Time `json:"expiresAt"` + + // accessRules is a list of fine grained access control rules + // +kubebuilder:validation:MaxItems:=64 + // +listType=atomic + // +optional + AccessRules []ApplicationCredentialAccessRuleStatus `json:"accessRules,omitempty"` +} diff --git a/api/v1alpha1/conditions.go b/api/v1alpha1/conditions.go index 93dfe7712..4acd7f1f0 100644 --- a/api/v1alpha1/conditions.go +++ b/api/v1alpha1/conditions.go @@ -113,7 +113,7 @@ func GetTerminalError(obj ObjectWithConditions) error { return nil } -func IsAvailable(obj ObjectWithConditions) bool { +func IsAvailable[T ObjectWithConditions](obj T) bool { conditions := obj.GetConditions() available := meta.FindStatusCondition(conditions, ConditionAvailable) diff --git a/api/v1alpha1/endpoint_types.go b/api/v1alpha1/endpoint_types.go new file mode 100644 index 000000000..fc2e9c5cc --- /dev/null +++ b/api/v1alpha1/endpoint_types.go @@ -0,0 +1,92 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +// EndpointResourceSpec contains the desired state of the resource. +type EndpointResourceSpec struct { + // description is a human-readable description for the resource. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="description is immutable" + Description *string `json:"description,omitempty"` + + // enabled indicates whether the endpoint is enabled or not. + // +optional + Enabled *bool `json:"enabled,omitempty"` + + // interface indicates the visibility of the endpoint. + // +kubebuilder:validation:Enum:=admin;internal;public + // +required + Interface string `json:"interface,omitempty"` + + // url is the endpoint URL. + // +kubebuilder:validation:MaxLength=1024 + // +required + URL string `json:"url"` + + // serviceRef is a reference to the ORC Service which this resource is associated with. + // +required + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="serviceRef is immutable" + ServiceRef KubernetesNameRef `json:"serviceRef,omitempty"` +} + +// EndpointFilter defines an existing resource by its properties +// +kubebuilder:validation:MinProperties:=1 +type EndpointFilter struct { + // interface of the existing endpoint. + // +kubebuilder:validation:Enum:=admin;internal;public + // +optional + Interface string `json:"interface,omitempty"` + + // serviceRef is a reference to the ORC Service which this resource is associated with. + // +optional + ServiceRef *KubernetesNameRef `json:"serviceRef,omitempty"` + + // url is the URL of the existing endpoint. + // +kubebuilder:validation:MaxLength=1024 + // +optional + URL string `json:"url,omitempty"` +} + +// EndpointResourceStatus represents the observed state of the resource. +type EndpointResourceStatus struct { + // description is a human-readable description for the resource. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + Description string `json:"description,omitempty"` + + // enabled indicates whether the endpoint is enabled or not. + // +optional + Enabled *bool `json:"enabled,omitempty"` + + // interface indicates the visibility of the endpoint. + // +kubebuilder:validation:MaxLength=128 + // +optional + Interface string `json:"interface,omitempty"` + + // url is the endpoint URL. + // +kubebuilder:validation:MaxLength=1024 + // +optional + URL string `json:"url,omitempty"` + + // serviceID is the ID of the Service to which the resource is associated. + // +kubebuilder:validation:MaxLength=1024 + // +optional + ServiceID string `json:"serviceID,omitempty"` +} diff --git a/api/v1alpha1/flavor_types.go b/api/v1alpha1/flavor_types.go index 991133619..c6d6479bb 100644 --- a/api/v1alpha1/flavor_types.go +++ b/api/v1alpha1/flavor_types.go @@ -17,26 +17,38 @@ limitations under the License. package v1alpha1 // FlavorResourceSpec contains the desired state of a flavor -// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="FlavorResourceSpec is immutable" type FlavorResourceSpec struct { // name will be the name of the created resource. If not specified, the // name of the ORC object will be used. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="name is immutable" // +optional Name *OpenStackName `json:"name,omitempty"` + // id will be the id of the created resource. If not specified, a random + // UUID will be generated by OpenStack. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=255 + // +kubebuilder:validation:Pattern=^[a-zA-Z0-9._-]([a-zA-Z0-9. _-]*[a-zA-Z0-9._-])?$ + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="id is immutable" + // +optional + ID string `json:"id,omitempty"` //nolint:kubeapilinter // intentionally allow raw ID + // description contains a free form description of the flavor. // +kubebuilder:validation:MinLength:=1 // +kubebuilder:validation:MaxLength:=65535 + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="description is immutable" // +optional Description *string `json:"description,omitempty"` // ram is the memory of the flavor, measured in MB. // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ram is immutable" // +required RAM int32 `json:"ram,omitempty"` // vcpus is the number of vcpus for the flavor. // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="vcpus is immutable" // +required Vcpus int32 `json:"vcpus,omitempty"` @@ -49,16 +61,26 @@ type FlavorResourceSpec struct { // zero root disk via the // os_compute_api:servers:create:zero_disk_flavor policy rule. // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="disk is immutable" // +required Disk int32 `json:"disk"` // swap is the size of a dedicated swap disk that will be allocated, in // MiB. If 0 (the default), no dedicated swap disk will be created. // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="swap is immutable" // +optional Swap int32 `json:"swap,omitempty"` + // extraSpecs is a list of key-value pairs that define extra specifications for the flavor. + // +kubebuilder:validation:MaxItems:=128 + // +listType=map + // +listMapKey=name + // +optional + ExtraSpecs []FlavorExtraSpec `json:"extraSpecs,omitempty"` + // isPublic flags a flavor as being available to all projects or not. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="isPublic is immutable" // +optional IsPublic *bool `json:"isPublic,omitempty"` @@ -67,6 +89,7 @@ type FlavorResourceSpec struct { // be used as a scratch space for applications that are aware of its // limitations. Defaults to 0. // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ephemeral is immutable" // +optional Ephemeral int32 `json:"ephemeral,omitempty"` } @@ -123,6 +146,12 @@ type FlavorResourceStatus struct { // +optional Swap *int32 `json:"swap,omitempty"` + // extraSpecs is a map of key-value pairs that define extra specifications for the flavor. + // +kubebuilder:validation:MaxItems:=128 + // +listType=atomic + // +optional + ExtraSpecs []FlavorExtraSpecStatus `json:"extraSpecs"` + // isPublic flags a flavor as being available to all projects or not. // +optional IsPublic *bool `json:"isPublic,omitempty"` @@ -131,3 +160,28 @@ type FlavorResourceStatus struct { // +optional Ephemeral *int32 `json:"ephemeral,omitempty"` } + +type FlavorExtraSpec struct { + // name is the name of the extraspec + // +kubebuilder:validation:Pattern="^[a-zA-Z0-9-_:. ]+$" + // +kubebuilder:validation:MaxLength:=255 + // +required + Name string `json:"name"` + + // value is the value of the extraspec + // +kubebuilder:validation:MaxLength:=255 + // +required + Value string `json:"value"` +} + +type FlavorExtraSpecStatus struct { + // name is the name of the extraspec + // +kubebuilder:validation:MaxLength:=255 + // +optional + Name string `json:"name,omitempty"` + + // value is the value of the extraspec + // +kubebuilder:validation:MaxLength:=255 + // +optional + Value string `json:"value,omitempty"` +} diff --git a/api/v1alpha1/image_types.go b/api/v1alpha1/image_types.go index b05992d78..de6014973 100644 --- a/api/v1alpha1/image_types.go +++ b/api/v1alpha1/image_types.go @@ -267,8 +267,7 @@ type ImageContent struct { // download describes how to obtain image data by downloading it from a URL. // Must be set when creating a managed image. // +required - //nolint:kubeapilinter - Download *ImageContentSourceDownload `json:"download"` + Download *ImageContentSourceDownload `json:"download,omitempty"` } type ImageContentSourceDownload struct { diff --git a/api/v1alpha1/port_types.go b/api/v1alpha1/port_types.go index 868748c17..108dc8c5f 100644 --- a/api/v1alpha1/port_types.go +++ b/api/v1alpha1/port_types.go @@ -41,9 +41,34 @@ type PortFilter struct { // +optional AdminStateUp *bool `json:"adminStateUp,omitempty"` + // macAddress is the MAC address of the port. + // +kubebuilder:validation:MaxLength=32 + // +optional + MACAddress string `json:"macAddress,omitempty"` + FilterByNeutronTags `json:",inline"` } +// HostID specifies how to determine the host ID for port binding. +// Exactly one of the fields must be set. +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +// +kubebuilder:validation:XValidation:rule="(has(self.id) && size(self.id) > 0) != (has(self.serverRef) && size(self.serverRef) > 0)",message="exactly one of id or serverRef must be set" +type HostID struct { + // id is the literal host ID string to use for binding:host_id. + // This is mutually exclusive with serverRef. + // +kubebuilder:validation:MaxLength=36 + // +optional + ID string `json:"id,omitempty"` //nolint:kubeapilinter // intentionally allow raw ID + + // serverRef is a reference to an ORC Server resource from which to + // retrieve the hostID for port binding. The hostID will be read from + // the Server's status.resource.hostID field. + // This is mutually exclusive with id. + // +optional + ServerRef KubernetesNameRef `json:"serverRef,omitempty"` +} + type AllowedAddressPair struct { // ip contains an IP address which a server connected to the port can // send packets with. It can be an IP Address or a CIDR (if supported @@ -96,6 +121,19 @@ type FixedIPStatus struct { SubnetID string `json:"subnetID,omitempty"` } +type PortValueSpec struct { + // key is the name of the Neutron API extension parameter. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +required + Key string `json:"key,omitempty"` + + // value is the value of the Neutron API extension parameter. + // +kubebuilder:validation:MaxLength:=255 + // +required + Value *string `json:"value,omitempty"` +} + // +kubebuilder:validation:XValidation:rule="has(self.portSecurity) && self.portSecurity == 'Disabled' ? !has(self.securityGroupRefs) : true",message="securityGroupRefs must be empty when portSecurity is set to Disabled" // +kubebuilder:validation:XValidation:rule="has(self.portSecurity) && self.portSecurity == 'Disabled' ? !has(self.allowedAddressPairs) : true",message="allowedAddressPairs must be empty when portSecurity is set to Disabled" type PortResourceSpec struct { @@ -137,12 +175,12 @@ type PortResourceSpec struct { // +optional AdminStateUp *bool `json:"adminStateUp,omitempty"` - // securityGroupRefs are the names of the security groups associated + // securityGroupRefs are references to the security groups associated // with this port. // +kubebuilder:validation:MaxItems:=64 // +listType=set // +optional - SecurityGroupRefs []OpenStackName `json:"securityGroupRefs,omitempty"` + SecurityGroupRefs []KubernetesNameRef `json:"securityGroupRefs,omitempty"` // vnicType specifies the type of vNIC which this port should be // attached to. This is used to determine which mechanism driver(s) to @@ -170,6 +208,51 @@ type PortResourceSpec struct { // +optional // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="projectRef is immutable" ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` + + // macAddress is the MAC address of the port. + // +kubebuilder:validation:MaxLength=32 + // +optional + MACAddress string `json:"macAddress,omitempty"` + + // hostID specifies the host where the port will be bound. + // Note that when the port is attached to a server, OpenStack may + // rebind the port to the server's actual compute host, which may + // differ from the specified hostID if no matching scheduler hint + // is used. In this case the port's status will reflect the actual + // binding host, not the value specified here. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="hostID is immutable" + HostID *HostID `json:"hostID,omitempty"` //nolint:kubeapilinter // HostID provides both raw ID and ServerRef options + + // trustedVIF indicates whether the VF for the port will become + // trusted by physical function to perform some privileged + // operations. Only admin users can create ports with this field. + // +optional + TrustedVIF *bool `json:"trustedVIF,omitempty"` + + // valueSpecs are extra parameters to include in the API request + // with OpenStack. This is an extension point for the API, so what + // they do and if they are supported, depends on the specific + // OpenStack implementation. This was meant to work similar to the + // property on Heat port resource. Since this depends on the + // underlying implementation, we can't predict its fields, and + // therefore, we don't know how to reconcile them in advance. Use + // this field wisely and be aware of the expected behavior. + // +kubebuilder:validation:MaxItems:=128 + // +listType=map + // +listMapKey=key + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="valueSpecs is immutable" + ValueSpecs []PortValueSpec `json:"valueSpecs,omitempty"` + + // propagateUplinkStatus represents the uplink status propagation of + // the port. + // The field is now immutable due to a limitation on + // Dalmatian (2024.2) release, we should address this later. + // https://github.com/k-orc/openstack-resource-controller/pull/641#discussion_r2694783787 + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="propagateUplinkStatus is immutable" + PropagateUplinkStatus *bool `json:"propagateUplinkStatus,omitempty"` } type PortResourceStatus struct { @@ -262,6 +345,17 @@ type PortResourceStatus struct { // +optional PortSecurityEnabled *bool `json:"portSecurityEnabled,omitempty"` + // hostID is the ID of host where the port resides. + // +kubebuilder:validation:MaxLength=128 + // +optional + HostID string `json:"hostID,omitempty"` + + // trustedVIF indicates whether the VF for the port will become + // trusted by physical function to perform some privileged + // operations. + // +optional + TrustedVIF *bool `json:"trustedVIF,omitempty"` + NeutronStatusMetadata `json:",inline"` } diff --git a/api/v1alpha1/project_types.go b/api/v1alpha1/project_types.go index 3fa321c79..0c49011c9 100644 --- a/api/v1alpha1/project_types.go +++ b/api/v1alpha1/project_types.go @@ -64,6 +64,11 @@ type ProjectResourceSpec struct { // +optional Description *string `json:"description,omitempty"` + // domainRef is a reference to the ORC Domain which this resource is associated with. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="domainRef is immutable" + DomainRef *KubernetesNameRef `json:"domainRef,omitempty"` + // enabled defines whether a project is enabled or not. Default is true. // +optional Enabled *bool `json:"enabled,omitempty"` @@ -83,6 +88,10 @@ type ProjectFilter struct { // +optional Name *KeystoneName `json:"name,omitempty"` + // domainRef is a reference to the ORC Domain which this resource is associated with. + // +optional + DomainRef *KubernetesNameRef `json:"domainRef,omitempty"` + FilterByKeystoneTags `json:",inline"` } @@ -98,6 +107,11 @@ type ProjectResourceStatus struct { // +optional Description string `json:"description,omitempty"` + // domainID is the ID of the Domain to which the resource is associated. + // +kubebuilder:validation:MaxLength=1024 + // +optional + DomainID string `json:"domainID,omitempty"` + // enabled represents whether a project is enabled or not. // +optional Enabled *bool `json:"enabled,omitempty"` diff --git a/api/v1alpha1/roleassignment_types.go b/api/v1alpha1/roleassignment_types.go new file mode 100644 index 000000000..b2a947975 --- /dev/null +++ b/api/v1alpha1/roleassignment_types.go @@ -0,0 +1,104 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +// RoleAssignmentResourceSpec defines the desired role assignment. +// A role assignment grants a role to a user or group on a project or domain. +// Role assignments are immutable once created and identified by the combination +// of (role, actor, scope) rather than a separate ID. +// +kubebuilder:validation:XValidation:rule="(has(self.userRef) && !has(self.groupRef)) || (!has(self.userRef) && has(self.groupRef))",message="exactly one of userRef or groupRef is required" +// +kubebuilder:validation:XValidation:rule="(has(self.projectRef) && !has(self.domainRef)) || (!has(self.projectRef) && has(self.domainRef))",message="exactly one of projectRef or domainRef is required" +// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="RoleAssignmentResourceSpec is immutable" +type RoleAssignmentResourceSpec struct { + // roleRef references the Role being assigned. + // +required + RoleRef KubernetesNameRef `json:"roleRef,omitempty"` + + // userRef references the User receiving the role assignment. + // Exactly one of userRef or groupRef must be specified. + // +optional + UserRef *KubernetesNameRef `json:"userRef,omitempty"` + + // groupRef references the Group receiving the role assignment. + // Exactly one of userRef or groupRef must be specified. + // +optional + GroupRef *KubernetesNameRef `json:"groupRef,omitempty"` + + // projectRef references the Project scope for the assignment. + // Exactly one of projectRef or domainRef must be specified. + // +optional + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` + + // domainRef references the Domain scope for the assignment. + // Exactly one of projectRef or domainRef must be specified. + // +optional + DomainRef *KubernetesNameRef `json:"domainRef,omitempty"` +} + +// RoleAssignmentFilter defines import filter criteria for existing role assignments. +// +kubebuilder:validation:MinProperties:=1 +type RoleAssignmentFilter struct { + // roleRef filters by the referenced Role. + // +optional + RoleRef *KubernetesNameRef `json:"roleRef,omitempty"` + + // userRef filters by the referenced User. + // +optional + UserRef *KubernetesNameRef `json:"userRef,omitempty"` + + // groupRef filters by the referenced Group. + // +optional + GroupRef *KubernetesNameRef `json:"groupRef,omitempty"` + + // projectRef filters by the referenced Project scope. + // +optional + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` + + // domainRef filters by the referenced Domain scope. + // +optional + DomainRef *KubernetesNameRef `json:"domainRef,omitempty"` +} + +// RoleAssignmentResourceStatus represents the observed state of the role assignment. +// Note: Role assignments do not have a unique ID in OpenStack - they are identified +// by the combination of role, actor (user/group), and scope (project/domain). +type RoleAssignmentResourceStatus struct { + // roleID is the OpenStack ID of the assigned role. + // +kubebuilder:validation:MaxLength=1024 + // +optional + RoleID string `json:"roleID,omitempty"` + + // userID is the OpenStack ID of the user (if actorType is User). + // +kubebuilder:validation:MaxLength=1024 + // +optional + UserID string `json:"userID,omitempty"` + + // groupID is the OpenStack ID of the group (if actorType is Group). + // +kubebuilder:validation:MaxLength=1024 + // +optional + GroupID string `json:"groupID,omitempty"` + + // projectID is the OpenStack ID of the project scope (if scopeType is Project). + // +kubebuilder:validation:MaxLength=1024 + // +optional + ProjectID string `json:"projectID,omitempty"` + + // domainID is the OpenStack ID of the domain scope (if scopeType is Domain). + // +kubebuilder:validation:MaxLength=1024 + // +optional + DomainID string `json:"domainID,omitempty"` +} diff --git a/api/v1alpha1/router_interface_types.go b/api/v1alpha1/router_interface_types.go index 2676d07bd..2506e5610 100644 --- a/api/v1alpha1/router_interface_types.go +++ b/api/v1alpha1/router_interface_types.go @@ -36,8 +36,8 @@ type RouterInterface struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec RouterInterfaceSpec `json:"spec,omitempty"` + // +required + Spec RouterInterfaceSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional @@ -74,7 +74,9 @@ const ( ) // +kubebuilder:validation:XValidation:rule="self.type == 'Subnet' ? has(self.subnetRef) : !has(self.subnetRef)",message="subnetRef is required when type is 'Subnet' and not permitted otherwise" -// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="RouterInterfaceResourceSpec is immutable" +// +kubebuilder:validation:XValidation:rule="self.type == oldSelf.type",message="type is immutable" +// +kubebuilder:validation:XValidation:rule="self.routerRef == oldSelf.routerRef",message="routerRef is immutable" +// +kubebuilder:validation:XValidation:rule="has(self.subnetRef) == has(oldSelf.subnetRef) && (!has(self.subnetRef) || self.subnetRef == oldSelf.subnetRef)",message="subnetRef is immutable" type RouterInterfaceSpec struct { // type specifies the type of the router interface. // +required @@ -89,6 +91,14 @@ type RouterInterfaceSpec struct { // +unionMember // +optional SubnetRef *KubernetesNameRef `json:"subnetRef,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config } type RouterInterfaceStatus struct { @@ -118,9 +128,14 @@ type RouterInterfaceStatus struct { // +kubebuilder:validation:MaxLength=1024 // +optional ID *string `json:"id,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // of the resource. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } -var _ ObjectWithConditions = &Router{} +var _ ObjectWithConditions = &RouterInterface{} func (i *RouterInterface) GetConditions() []metav1.Condition { return i.Status.Conditions diff --git a/api/v1alpha1/server_types.go b/api/v1alpha1/server_types.go index 7fefa5f38..af3aa8fee 100644 --- a/api/v1alpha1/server_types.go +++ b/api/v1alpha1/server_types.go @@ -60,6 +60,20 @@ type ServerPortSpec struct { PortRef *KubernetesNameRef `json:"portRef,omitempty"` } +// ServerBootVolumeSpec defines the boot volume for boot-from-volume server creation. +// When specified, the server boots from this volume instead of an image. +type ServerBootVolumeSpec struct { + // volumeRef is a reference to a Volume object. The volume must be + // bootable (created from an image) and available before server creation. + // +required + VolumeRef KubernetesNameRef `json:"volumeRef,omitempty"` + + // tag is the device tag applied to the volume. + // +kubebuilder:validation:MaxLength:=255 + // +optional + Tag *string `json:"tag,omitempty"` +} + // +kubebuilder:validation:MinProperties:=1 type ServerVolumeSpec struct { // volumeRef is a reference to a Volume object. Server creation will wait for @@ -122,6 +136,8 @@ type ServerInterfaceStatus struct { } // ServerResourceSpec contains the desired state of a server +// +kubebuilder:validation:XValidation:rule="has(self.imageRef) || has(self.bootVolume)",message="either imageRef or bootVolume must be specified" +// +kubebuilder:validation:XValidation:rule="!(has(self.imageRef) && has(self.bootVolume))",message="imageRef and bootVolume are mutually exclusive" type ServerResourceSpec struct { // name will be the name of the created resource. If not specified, the // name of the ORC object will be used. @@ -129,16 +145,23 @@ type ServerResourceSpec struct { Name *OpenStackName `json:"name,omitempty"` // imageRef references the image to use for the server instance. - // NOTE: This is not required in case of boot from volume. - // +required + // This field is required unless bootVolume is specified for boot-from-volume. + // +optional // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="imageRef is immutable" - ImageRef KubernetesNameRef `json:"imageRef,omitempty"` + ImageRef *KubernetesNameRef `json:"imageRef,omitempty"` // flavorRef references the flavor to use for the server instance. // +required // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="flavorRef is immutable" FlavorRef KubernetesNameRef `json:"flavorRef,omitempty"` + // bootVolume specifies a volume to boot from instead of an image. + // When specified, imageRef must be omitted. The volume must be + // bootable (created from an image using imageRef in the Volume spec). + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="bootVolume is immutable" + BootVolume *ServerBootVolumeSpec `json:"bootVolume,omitempty"` + // userData specifies data which will be made available to the server at // boot time, either via the metadata service or a config drive. It is // typically read by a configuration service such as cloud-init or ignition. @@ -158,12 +181,6 @@ type ServerResourceSpec struct { // +optional Volumes []ServerVolumeSpec `json:"volumes,omitempty"` - // serverGroupRef is a reference to a ServerGroup object. The server - // will be created in the server group. - // +optional - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="serverGroupRef is immutable" - ServerGroupRef *KubernetesNameRef `json:"serverGroupRef,omitempty"` - // availabilityZone is the availability zone in which to create the server. // +kubebuilder:validation:MaxLength=255 // +optional @@ -181,10 +198,94 @@ type ServerResourceSpec struct { // +listType=set // +optional Tags []ServerTag `json:"tags,omitempty"` + + // metadata is a list of metadata key-value pairs which will be set on the server. + // +kubebuilder:validation:MaxItems:=128 + // +listType=atomic + // +optional + Metadata []ServerMetadata `json:"metadata,omitempty"` + + // configDrive specifies whether to attach a config drive to the server. + // When true, configuration data will be available via a special drive + // instead of the metadata service. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="configDrive is immutable" + ConfigDrive *bool `json:"configDrive,omitempty"` + + // schedulerHints provides hints to the Nova scheduler for server placement. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="schedulerHints is immutable" + SchedulerHints *ServerSchedulerHints `json:"schedulerHints,omitempty"` +} + +// ServerMetadata represents a key-value pair for server metadata. +type ServerMetadata struct { + // key is the metadata key. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +required + Key string `json:"key,omitempty"` + + // value is the metadata value. + // +kubebuilder:validation:MaxLength:=255 + // +kubebuilder:validation:MinLength:=1 + // +required + Value string `json:"value,omitempty"` +} + +// ServerSchedulerHints provides hints to the Nova scheduler for server placement. +type ServerSchedulerHints struct { + // serverGroupRef is a reference to a ServerGroup object. The server will be + // scheduled on a host in the specified server group. + // +optional + ServerGroupRef *KubernetesNameRef `json:"serverGroupRef,omitempty"` + + // differentHostServerRefs is a list of references to Server objects. + // The server will be scheduled on a different host than all specified servers. + // +listType=set + // +kubebuilder:validation:MaxItems:=64 + // +optional + DifferentHostServerRefs []KubernetesNameRef `json:"differentHostServerRefs,omitempty"` + + // sameHostServerRefs is a list of references to Server objects. + // The server will be scheduled on the same host as all specified servers. + // +listType=set + // +kubebuilder:validation:MaxItems:=64 + // +optional + SameHostServerRefs []KubernetesNameRef `json:"sameHostServerRefs,omitempty"` + + // query is a conditional statement that results in compute nodes + // able to host the server. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + Query string `json:"query,omitempty"` + + // targetCell is a cell name where the server will be placed. + // +kubebuilder:validation:MaxLength:=255 + // +optional + TargetCell string `json:"targetCell,omitempty"` + + // differentCell is a list of cell names where the server should not + // be placed. + // +listType=set + // +kubebuilder:validation:MaxItems:=64 + // +kubebuilder:validation:items:MaxLength=1024 + // +optional + DifferentCell []string `json:"differentCell,omitempty"` + + // buildNearHostIP specifies a subnet of compute nodes to host the server. + // The host IP should be provided in an CIDR format like 10.10.10.10/24. + // +optional + BuildNearHostIP *CIDR `json:"buildNearHostIP,omitempty"` + + // additionalProperties is a map of arbitrary key/value pairs that are + // not validated by Nova. + // +optional + AdditionalProperties map[string]string `json:"additionalProperties,omitempty"` } -// +kubebuilder:validation:MinProperties:=1 // +kubebuilder:validation:MaxProperties:=1 +// +kubebuilder:validation:MinProperties:=1 type UserDataSpec struct { // secretRef is a reference to a Secret containing the user data for this server. // +optional @@ -261,4 +362,27 @@ type ServerResourceStatus struct { // +listType=atomic // +optional Tags []string `json:"tags,omitempty"` + + // metadata is the list of metadata key-value pairs on the resource. + // +kubebuilder:validation:MaxItems:=128 + // +listType=atomic + // +optional + Metadata []ServerMetadataStatus `json:"metadata,omitempty"` + + // configDrive indicates whether the server was booted with a config drive. + // +optional + ConfigDrive bool `json:"configDrive,omitempty"` +} + +// ServerMetadataStatus represents a key-value pair for server metadata in status. +type ServerMetadataStatus struct { + // key is the metadata key. + // +kubebuilder:validation:MaxLength:=255 + // +optional + Key string `json:"key,omitempty"` + + // value is the metadata value. + // +kubebuilder:validation:MaxLength:=255 + // +optional + Value string `json:"value,omitempty"` } diff --git a/api/v1alpha1/sharenetwork_types.go b/api/v1alpha1/sharenetwork_types.go new file mode 100644 index 000000000..83ef4dfca --- /dev/null +++ b/api/v1alpha1/sharenetwork_types.go @@ -0,0 +1,112 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// ShareNetworkResourceSpec contains the desired state of the resource. +// +kubebuilder:validation:XValidation:rule="has(self.networkRef) == has(self.subnetRef)",message="networkRef and subnetRef must be specified together" +type ShareNetworkResourceSpec struct { + // name will be the name of the created resource. If not specified, the + // name of the ORC object will be used. + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + Description *string `json:"description,omitempty"` + + // networkRef is a reference to the ORC Network which this resource is associated with. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="networkRef is immutable" + NetworkRef *KubernetesNameRef `json:"networkRef,omitempty"` + + // subnetRef is a reference to the ORC Subnet which this resource is associated with. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="subnetRef is immutable" + SubnetRef *KubernetesNameRef `json:"subnetRef,omitempty"` +} + +// ShareNetworkFilter defines an existing resource by its properties +// +kubebuilder:validation:MinProperties:=1 +type ShareNetworkFilter struct { + // name of the existing resource + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description of the existing resource + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + Description *string `json:"description,omitempty"` +} + +// ShareNetworkResourceStatus represents the observed state of the resource. +type ShareNetworkResourceStatus struct { + // name is a Human-readable name for the resource. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Name string `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Description string `json:"description,omitempty"` + + // neutronNetID is the Neutron network ID. + // +kubebuilder:validation:MaxLength=1024 + // +optional + NeutronNetID string `json:"neutronNetID,omitempty"` + + // neutronSubnetID is the Neutron subnet ID. + // +kubebuilder:validation:MaxLength=1024 + // +optional + NeutronSubnetID string `json:"neutronSubnetID,omitempty"` + + // networkType is the network type (e.g., vlan, vxlan, flat). + // +kubebuilder:validation:MaxLength=1024 + // +optional + NetworkType string `json:"networkType,omitempty"` + + // segmentationID is the segmentation ID of the network. + // +optional + SegmentationID *int32 `json:"segmentationID,omitempty"` + + // cidr is the CIDR of the subnet. + // +kubebuilder:validation:MaxLength=1024 + // +optional + CIDR string `json:"cidr"` + + // ipVersion is the IP version (4 or 6). + // +optional + IPVersion *int32 `json:"ipVersion,omitempty"` + + // projectID is the ID of the project that owns the share network. + // +kubebuilder:validation:MaxLength=1024 + // +optional + ProjectID string `json:"projectID,omitempty"` + + // createdAt shows the date and time when the resource was created. + // +optional + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + + // updatedAt shows the date and time when the resource was updated. + // +optional + UpdatedAt *metav1.Time `json:"updatedAt,omitempty"` +} diff --git a/api/v1alpha1/trunk_types.go b/api/v1alpha1/trunk_types.go new file mode 100644 index 000000000..d857c4501 --- /dev/null +++ b/api/v1alpha1/trunk_types.go @@ -0,0 +1,176 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +// TrunkSubportSpec represents a subport to attach to a trunk. +// It maps to gophercloud's trunks.Subport. +type TrunkSubportSpec struct { + // portRef is a reference to the ORC Port that will be attached as a subport. + // +required + PortRef KubernetesNameRef `json:"portRef,omitempty"` + + // segmentationID is the segmentation ID for the subport (e.g. VLAN ID). + // +required + // +kubebuilder:validation:Minimum:=1 + // +kubebuilder:validation:Maximum:=4094 + SegmentationID int32 `json:"segmentationID,omitempty"` + + // segmentationType is the segmentation type for the subport (e.g. vlan). + // +required + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=32 + // +kubebuilder:validation:Enum:=inherit;vlan + SegmentationType string `json:"segmentationType,omitempty"` +} + +// TrunkSubportStatus represents an attached subport on a trunk. +// It maps to gophercloud's trunks.Subport. +type TrunkSubportStatus struct { + // portID is the OpenStack ID of the Port attached as a subport. + // +kubebuilder:validation:MaxLength=1024 + // +optional + PortID string `json:"portID,omitempty"` + + // segmentationID is the segmentation ID for the subport (e.g. VLAN ID). + // +optional + SegmentationID int32 `json:"segmentationID,omitempty"` + + // segmentationType is the segmentation type for the subport (e.g. vlan). + // +kubebuilder:validation:MaxLength=1024 + // +optional + SegmentationType string `json:"segmentationType,omitempty"` +} + +// TrunkResourceSpec contains the desired state of the resource. +type TrunkResourceSpec struct { + // name will be the name of the created resource. If not specified, the + // name of the ORC object will be used. + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +optional + Description *NeutronDescription `json:"description,omitempty"` + + // portRef is a reference to the ORC Port which this resource is associated with. + // +required + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="portRef is immutable" + PortRef KubernetesNameRef `json:"portRef,omitempty"` + + // projectRef is a reference to the ORC Project which this resource is associated with. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="projectRef is immutable" + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` + + // adminStateUp is the administrative state of the trunk. If false (down), + // the trunk does not forward packets. + // +optional + AdminStateUp *bool `json:"adminStateUp,omitempty"` + + // subports is the list of ports to attach to the trunk. + // +optional + // +kubebuilder:validation:MaxItems:=1024 + // +listType=atomic + Subports []TrunkSubportSpec `json:"subports,omitempty"` + + // tags is a list of Neutron tags to apply to the trunk. + // +kubebuilder:validation:MaxItems:=64 + // +listType=set + // +optional + Tags []NeutronTag `json:"tags,omitempty"` +} + +// TrunkFilter defines an existing resource by its properties +// +kubebuilder:validation:MinProperties:=1 +type TrunkFilter struct { + // name of the existing resource + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description of the existing resource + // +optional + Description *NeutronDescription `json:"description,omitempty"` + + // portRef is a reference to the ORC Port which this resource is associated with. + // +optional + PortRef *KubernetesNameRef `json:"portRef,omitempty"` + + // projectRef is a reference to the ORC Project which this resource is associated with. + // +optional + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` + + // Contrary to what the neutron doc say, we can't filter by status + // https://github.com/gophercloud/gophercloud/issues/3626 + + // adminStateUp is the administrative state of the trunk. + // +optional + AdminStateUp *bool `json:"adminStateUp,omitempty"` + + FilterByNeutronTags `json:",inline"` +} + +// TrunkResourceStatus represents the observed state of the resource. +type TrunkResourceStatus struct { + // name is a Human-readable name for the resource. Might not be unique. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Name string `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Description string `json:"description,omitempty"` + + // portID is the ID of the Port to which the resource is associated. + // +kubebuilder:validation:MaxLength=1024 + // +optional + PortID string `json:"portID,omitempty"` + + // projectID is the ID of the Project to which the resource is associated. + // +kubebuilder:validation:MaxLength=1024 + // +optional + ProjectID string `json:"projectID,omitempty"` + + // tenantID is the project owner of the trunk (alias of projectID in some deployments). + // +kubebuilder:validation:MaxLength=1024 + // +optional + TenantID string `json:"tenantID,omitempty"` + + // status indicates whether the trunk is currently operational. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Status string `json:"status,omitempty"` + + // tags is the list of tags on the resource. + // +kubebuilder:validation:MaxItems=64 + // +kubebuilder:validation:items:MaxLength=1024 + // +listType=atomic + // +optional + Tags []string `json:"tags,omitempty"` + + NeutronStatusMetadata `json:",inline"` + + // adminStateUp is the administrative state of the trunk. + // +optional + AdminStateUp *bool `json:"adminStateUp,omitempty"` + + // subports is a list of ports associated with the trunk. + // +kubebuilder:validation:MaxItems=1024 + // +listType=atomic + // +optional + Subports []TrunkSubportStatus `json:"subports,omitempty"` +} diff --git a/api/v1alpha1/user_types.go b/api/v1alpha1/user_types.go new file mode 100644 index 000000000..e085006d9 --- /dev/null +++ b/api/v1alpha1/user_types.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +// UserResourceSpec contains the desired state of the resource. +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.passwordRef) || has(self.passwordRef)",message="passwordRef may not be removed once set" +type UserResourceSpec struct { + // name will be the name of the created resource. If not specified, the + // name of the ORC object will be used. + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + Description *string `json:"description,omitempty"` + + // domainRef is a reference to the ORC Domain which this resource is associated with. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="domainRef is immutable" + DomainRef *KubernetesNameRef `json:"domainRef,omitempty"` + + // defaultProjectRef is a reference to the Default Project which this resource is associated with. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="defaultProjectRef is immutable" + DefaultProjectRef *KubernetesNameRef `json:"defaultProjectRef,omitempty"` + + // enabled defines whether a user is enabled or disabled + // +optional + Enabled *bool `json:"enabled,omitempty"` + + // passwordRef is a reference to a Secret containing the password + // for this user. The Secret must contain a key named "password". + // If not specified, the user is created without a password. + // +optional + PasswordRef *KubernetesNameRef `json:"passwordRef,omitempty"` +} + +// UserFilter defines an existing resource by its properties +// +kubebuilder:validation:MinProperties:=1 +type UserFilter struct { + // name of the existing resource + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // domainRef is a reference to the ORC Domain which this resource is associated with. + // +optional + DomainRef *KubernetesNameRef `json:"domainRef,omitempty"` +} + +// UserResourceStatus represents the observed state of the resource. +type UserResourceStatus struct { + // name is a Human-readable name for the resource. Might not be unique. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Name string `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Description string `json:"description,omitempty"` + + // domainID is the ID of the Domain to which the resource is associated. + // +kubebuilder:validation:MaxLength=1024 + // +optional + DomainID string `json:"domainID,omitempty"` + + // defaultProjectID is the ID of the Default Project to which the user is associated with. + // +kubebuilder:validation:MaxLength=1024 + // +optional + DefaultProjectID string `json:"defaultProjectID,omitempty"` + + // enabled defines whether a user is enabled or disabled + // +optional + Enabled bool `json:"enabled,omitempty"` + + // passwordExpiresAt is the timestamp at which the user's password expires. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + PasswordExpiresAt string `json:"passwordExpiresAt,omitempty"` + + // appliedPasswordRef is the name of the Secret containing the + // password that was last applied to the OpenStack resource. + // +kubebuilder:validation:MaxLength=1024 + // +optional + AppliedPasswordRef string `json:"appliedPasswordRef,omitempty"` +} diff --git a/api/v1alpha1/volume_types.go b/api/v1alpha1/volume_types.go index f50f83daa..49e2f3d06 100644 --- a/api/v1alpha1/volume_types.go +++ b/api/v1alpha1/volume_types.go @@ -56,6 +56,13 @@ type VolumeResourceSpec struct { // +listType=atomic // +optional Metadata []VolumeMetadata `json:"metadata,omitempty"` + + // imageRef is a reference to an ORC Image. If specified, creates a + // bootable volume from this image. The volume size must be >= the + // image's min_disk requirement. + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="imageRef is immutable" + ImageRef *KubernetesNameRef `json:"imageRef,omitempty"` } // VolumeFilter defines an existing resource by its properties @@ -176,6 +183,11 @@ type VolumeResourceStatus struct { // +optional Bootable *bool `json:"bootable,omitempty"` + // imageID is the ID of the image this volume was created from, if any. + // +kubebuilder:validation:MaxLength=1024 + // +optional + ImageID string `json:"imageID,omitempty"` + // encrypted denotes if the volume is encrypted. // +optional Encrypted *bool `json:"encrypted,omitempty"` diff --git a/api/v1alpha1/zz_generated.addressscope-resource.go b/api/v1alpha1/zz_generated.addressscope-resource.go new file mode 100644 index 000000000..2ed71b9dd --- /dev/null +++ b/api/v1alpha1/zz_generated.addressscope-resource.go @@ -0,0 +1,194 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// AddressScopeImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type AddressScopeImport struct { + // id contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:Format:=uuid + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *AddressScopeFilter `json:"filter,omitempty"` +} + +// AddressScopeSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type AddressScopeSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *AddressScopeImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *AddressScopeResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// AddressScopeStatus defines the observed state of an ORC resource. +type AddressScopeStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *AddressScopeResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &AddressScope{} + +func (i *AddressScope) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// AddressScope is the Schema for an ORC resource. +type AddressScope struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec AddressScopeSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status AddressScopeStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// AddressScopeList contains a list of AddressScope. +type AddressScopeList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of AddressScope. + // +required + Items []AddressScope `json:"items"` +} + +func (l *AddressScopeList) GetItems() []AddressScope { + return l.Items +} + +func init() { + SchemeBuilder.Register(&AddressScope{}, &AddressScopeList{}) +} + +func (i *AddressScope) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &AddressScope{} diff --git a/api/v1alpha1/zz_generated.applicationcredential-resource.go b/api/v1alpha1/zz_generated.applicationcredential-resource.go new file mode 100644 index 000000000..36058ef73 --- /dev/null +++ b/api/v1alpha1/zz_generated.applicationcredential-resource.go @@ -0,0 +1,194 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ApplicationCredentialImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type ApplicationCredentialImport struct { + // id contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:Format:=uuid + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *ApplicationCredentialFilter `json:"filter,omitempty"` +} + +// ApplicationCredentialSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type ApplicationCredentialSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *ApplicationCredentialImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *ApplicationCredentialResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// ApplicationCredentialStatus defines the observed state of an ORC resource. +type ApplicationCredentialStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *ApplicationCredentialResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &ApplicationCredential{} + +func (i *ApplicationCredential) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// ApplicationCredential is the Schema for an ORC resource. +type ApplicationCredential struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec ApplicationCredentialSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status ApplicationCredentialStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ApplicationCredentialList contains a list of ApplicationCredential. +type ApplicationCredentialList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of ApplicationCredential. + // +required + Items []ApplicationCredential `json:"items"` +} + +func (l *ApplicationCredentialList) GetItems() []ApplicationCredential { + return l.Items +} + +func init() { + SchemeBuilder.Register(&ApplicationCredential{}, &ApplicationCredentialList{}) +} + +func (i *ApplicationCredential) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &ApplicationCredential{} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 093e63451..4e7d7e3c1 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -46,87 +46,7 @@ func (in *Address) DeepCopy() *Address { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AllocationPool) DeepCopyInto(out *AllocationPool) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllocationPool. -func (in *AllocationPool) DeepCopy() *AllocationPool { - if in == nil { - return nil - } - out := new(AllocationPool) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AllocationPoolStatus) DeepCopyInto(out *AllocationPoolStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllocationPoolStatus. -func (in *AllocationPoolStatus) DeepCopy() *AllocationPoolStatus { - if in == nil { - return nil - } - out := new(AllocationPoolStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AllowedAddressPair) DeepCopyInto(out *AllowedAddressPair) { - *out = *in - if in.MAC != nil { - in, out := &in.MAC, &out.MAC - *out = new(MAC) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedAddressPair. -func (in *AllowedAddressPair) DeepCopy() *AllowedAddressPair { - if in == nil { - return nil - } - out := new(AllowedAddressPair) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AllowedAddressPairStatus) DeepCopyInto(out *AllowedAddressPairStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedAddressPairStatus. -func (in *AllowedAddressPairStatus) DeepCopy() *AllowedAddressPairStatus { - if in == nil { - return nil - } - out := new(AllowedAddressPairStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CloudCredentialsReference) DeepCopyInto(out *CloudCredentialsReference) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudCredentialsReference. -func (in *CloudCredentialsReference) DeepCopy() *CloudCredentialsReference { - if in == nil { - return nil - } - out := new(CloudCredentialsReference) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Domain) DeepCopyInto(out *Domain) { +func (in *AddressScope) DeepCopyInto(out *AddressScope) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -134,18 +54,18 @@ func (in *Domain) DeepCopyInto(out *Domain) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Domain. -func (in *Domain) DeepCopy() *Domain { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScope. +func (in *AddressScope) DeepCopy() *AddressScope { if in == nil { return nil } - out := new(Domain) + out := new(AddressScope) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Domain) DeepCopyObject() runtime.Object { +func (in *AddressScope) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -153,32 +73,37 @@ func (in *Domain) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainFilter) DeepCopyInto(out *DomainFilter) { +func (in *AddressScopeFilter) DeepCopyInto(out *AddressScopeFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(KeystoneName) + *out = new(OpenStackName) **out = **in } - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.Shared != nil { + in, out := &in.Shared, &out.Shared *out = new(bool) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainFilter. -func (in *DomainFilter) DeepCopy() *DomainFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScopeFilter. +func (in *AddressScopeFilter) DeepCopy() *AddressScopeFilter { if in == nil { return nil } - out := new(DomainFilter) + out := new(AddressScopeFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainImport) DeepCopyInto(out *DomainImport) { +func (in *AddressScopeImport) DeepCopyInto(out *AddressScopeImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -187,47 +112,47 @@ func (in *DomainImport) DeepCopyInto(out *DomainImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(DomainFilter) + *out = new(AddressScopeFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainImport. -func (in *DomainImport) DeepCopy() *DomainImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScopeImport. +func (in *AddressScopeImport) DeepCopy() *AddressScopeImport { if in == nil { return nil } - out := new(DomainImport) + out := new(AddressScopeImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainList) DeepCopyInto(out *DomainList) { +func (in *AddressScopeList) DeepCopyInto(out *AddressScopeList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Domain, len(*in)) + *out = make([]AddressScope, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainList. -func (in *DomainList) DeepCopy() *DomainList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScopeList. +func (in *AddressScopeList) DeepCopy() *AddressScopeList { if in == nil { return nil } - out := new(DomainList) + out := new(AddressScopeList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *DomainList) DeepCopyObject() runtime.Object { +func (in *AddressScopeList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -235,66 +160,66 @@ func (in *DomainList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainResourceSpec) DeepCopyInto(out *DomainResourceSpec) { +func (in *AddressScopeResourceSpec) DeepCopyInto(out *AddressScopeResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(KeystoneName) + *out = new(OpenStackName) **out = **in } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(string) + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) **out = **in } - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled + if in.Shared != nil { + in, out := &in.Shared, &out.Shared *out = new(bool) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainResourceSpec. -func (in *DomainResourceSpec) DeepCopy() *DomainResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScopeResourceSpec. +func (in *AddressScopeResourceSpec) DeepCopy() *AddressScopeResourceSpec { if in == nil { return nil } - out := new(DomainResourceSpec) + out := new(AddressScopeResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainResourceStatus) DeepCopyInto(out *DomainResourceStatus) { +func (in *AddressScopeResourceStatus) DeepCopyInto(out *AddressScopeResourceStatus) { *out = *in - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled + if in.Shared != nil { + in, out := &in.Shared, &out.Shared *out = new(bool) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainResourceStatus. -func (in *DomainResourceStatus) DeepCopy() *DomainResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScopeResourceStatus. +func (in *AddressScopeResourceStatus) DeepCopy() *AddressScopeResourceStatus { if in == nil { return nil } - out := new(DomainResourceStatus) + out := new(AddressScopeResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainSpec) DeepCopyInto(out *DomainSpec) { +func (in *AddressScopeSpec) DeepCopyInto(out *AddressScopeSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(DomainImport) + *out = new(AddressScopeImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(DomainResourceSpec) + *out = new(AddressScopeResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -302,21 +227,26 @@ func (in *DomainSpec) DeepCopyInto(out *DomainSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainSpec. -func (in *DomainSpec) DeepCopy() *DomainSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScopeSpec. +func (in *AddressScopeSpec) DeepCopy() *AddressScopeSpec { if in == nil { return nil } - out := new(DomainSpec) + out := new(AddressScopeSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DomainStatus) DeepCopyInto(out *DomainStatus) { +func (in *AddressScopeStatus) DeepCopyInto(out *AddressScopeStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -332,235 +262,209 @@ func (in *DomainStatus) DeepCopyInto(out *DomainStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(DomainResourceStatus) + *out = new(AddressScopeResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainStatus. -func (in *DomainStatus) DeepCopy() *DomainStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddressScopeStatus. +func (in *AddressScopeStatus) DeepCopy() *AddressScopeStatus { if in == nil { return nil } - out := new(DomainStatus) + out := new(AddressScopeStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExternalGateway) DeepCopyInto(out *ExternalGateway) { +func (in *AllocationPool) DeepCopyInto(out *AllocationPool) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalGateway. -func (in *ExternalGateway) DeepCopy() *ExternalGateway { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllocationPool. +func (in *AllocationPool) DeepCopy() *AllocationPool { if in == nil { return nil } - out := new(ExternalGateway) + out := new(AllocationPool) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExternalGatewayStatus) DeepCopyInto(out *ExternalGatewayStatus) { +func (in *AllocationPoolStatus) DeepCopyInto(out *AllocationPoolStatus) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalGatewayStatus. -func (in *ExternalGatewayStatus) DeepCopy() *ExternalGatewayStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllocationPoolStatus. +func (in *AllocationPoolStatus) DeepCopy() *AllocationPoolStatus { if in == nil { return nil } - out := new(ExternalGatewayStatus) + out := new(AllocationPoolStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FilterByKeystoneTags) DeepCopyInto(out *FilterByKeystoneTags) { +func (in *AllowedAddressPair) DeepCopyInto(out *AllowedAddressPair) { *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]KeystoneTag, len(*in)) - copy(*out, *in) - } - if in.TagsAny != nil { - in, out := &in.TagsAny, &out.TagsAny - *out = make([]KeystoneTag, len(*in)) - copy(*out, *in) - } - if in.NotTags != nil { - in, out := &in.NotTags, &out.NotTags - *out = make([]KeystoneTag, len(*in)) - copy(*out, *in) - } - if in.NotTagsAny != nil { - in, out := &in.NotTagsAny, &out.NotTagsAny - *out = make([]KeystoneTag, len(*in)) - copy(*out, *in) + if in.MAC != nil { + in, out := &in.MAC, &out.MAC + *out = new(MAC) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterByKeystoneTags. -func (in *FilterByKeystoneTags) DeepCopy() *FilterByKeystoneTags { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedAddressPair. +func (in *AllowedAddressPair) DeepCopy() *AllowedAddressPair { if in == nil { return nil } - out := new(FilterByKeystoneTags) + out := new(AllowedAddressPair) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FilterByNeutronTags) DeepCopyInto(out *FilterByNeutronTags) { +func (in *AllowedAddressPairStatus) DeepCopyInto(out *AllowedAddressPairStatus) { *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } - if in.TagsAny != nil { - in, out := &in.TagsAny, &out.TagsAny - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } - if in.NotTags != nil { - in, out := &in.NotTags, &out.NotTags - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } - if in.NotTagsAny != nil { - in, out := &in.NotTagsAny, &out.NotTagsAny - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterByNeutronTags. -func (in *FilterByNeutronTags) DeepCopy() *FilterByNeutronTags { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedAddressPairStatus. +func (in *AllowedAddressPairStatus) DeepCopy() *AllowedAddressPairStatus { if in == nil { return nil } - out := new(FilterByNeutronTags) + out := new(AllowedAddressPairStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FilterByServerTags) DeepCopyInto(out *FilterByServerTags) { +func (in *ApplicationCredential) DeepCopyInto(out *ApplicationCredential) { *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]ServerTag, len(*in)) - copy(*out, *in) - } - if in.TagsAny != nil { - in, out := &in.TagsAny, &out.TagsAny - *out = make([]ServerTag, len(*in)) - copy(*out, *in) - } - if in.NotTags != nil { - in, out := &in.NotTags, &out.NotTags - *out = make([]ServerTag, len(*in)) - copy(*out, *in) - } - if in.NotTagsAny != nil { - in, out := &in.NotTagsAny, &out.NotTagsAny - *out = make([]ServerTag, len(*in)) - copy(*out, *in) - } + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterByServerTags. -func (in *FilterByServerTags) DeepCopy() *FilterByServerTags { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredential. +func (in *ApplicationCredential) DeepCopy() *ApplicationCredential { if in == nil { return nil } - out := new(FilterByServerTags) + out := new(ApplicationCredential) in.DeepCopyInto(out) return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FixedIPStatus) DeepCopyInto(out *FixedIPStatus) { - *out = *in +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationCredential) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FixedIPStatus. -func (in *FixedIPStatus) DeepCopy() *FixedIPStatus { +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationCredentialAccessRule) DeepCopyInto(out *ApplicationCredentialAccessRule) { + *out = *in + if in.Path != nil { + in, out := &in.Path, &out.Path + *out = new(string) + **out = **in + } + if in.Method != nil { + in, out := &in.Method, &out.Method + *out = new(HTTPMethod) + **out = **in + } + if in.ServiceRef != nil { + in, out := &in.ServiceRef, &out.ServiceRef + *out = new(KubernetesNameRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialAccessRule. +func (in *ApplicationCredentialAccessRule) DeepCopy() *ApplicationCredentialAccessRule { if in == nil { return nil } - out := new(FixedIPStatus) + out := new(ApplicationCredentialAccessRule) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Flavor) DeepCopyInto(out *Flavor) { +func (in *ApplicationCredentialAccessRuleStatus) DeepCopyInto(out *ApplicationCredentialAccessRuleStatus) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Path != nil { + in, out := &in.Path, &out.Path + *out = new(string) + **out = **in + } + if in.Method != nil { + in, out := &in.Method, &out.Method + *out = new(string) + **out = **in + } + if in.Service != nil { + in, out := &in.Service, &out.Service + *out = new(string) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Flavor. -func (in *Flavor) DeepCopy() *Flavor { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialAccessRuleStatus. +func (in *ApplicationCredentialAccessRuleStatus) DeepCopy() *ApplicationCredentialAccessRuleStatus { if in == nil { return nil } - out := new(Flavor) + out := new(ApplicationCredentialAccessRuleStatus) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Flavor) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlavorFilter) DeepCopyInto(out *FlavorFilter) { +func (in *ApplicationCredentialFilter) DeepCopyInto(out *ApplicationCredentialFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(OpenStackName) **out = **in } - if in.RAM != nil { - in, out := &in.RAM, &out.RAM - *out = new(int32) - **out = **in - } - if in.Vcpus != nil { - in, out := &in.Vcpus, &out.Vcpus - *out = new(int32) - **out = **in - } - if in.Disk != nil { - in, out := &in.Disk, &out.Disk - *out = new(int32) + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorFilter. -func (in *FlavorFilter) DeepCopy() *FlavorFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialFilter. +func (in *ApplicationCredentialFilter) DeepCopy() *ApplicationCredentialFilter { if in == nil { return nil } - out := new(FlavorFilter) + out := new(ApplicationCredentialFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlavorImport) DeepCopyInto(out *FlavorImport) { +func (in *ApplicationCredentialImport) DeepCopyInto(out *ApplicationCredentialImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -569,47 +473,47 @@ func (in *FlavorImport) DeepCopyInto(out *FlavorImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(FlavorFilter) + *out = new(ApplicationCredentialFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorImport. -func (in *FlavorImport) DeepCopy() *FlavorImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialImport. +func (in *ApplicationCredentialImport) DeepCopy() *ApplicationCredentialImport { if in == nil { return nil } - out := new(FlavorImport) + out := new(ApplicationCredentialImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlavorList) DeepCopyInto(out *FlavorList) { +func (in *ApplicationCredentialList) DeepCopyInto(out *ApplicationCredentialList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Flavor, len(*in)) + *out = make([]ApplicationCredential, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorList. -func (in *FlavorList) DeepCopy() *FlavorList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialList. +func (in *ApplicationCredentialList) DeepCopy() *ApplicationCredentialList { if in == nil { return nil } - out := new(FlavorList) + out := new(ApplicationCredentialList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FlavorList) DeepCopyObject() runtime.Object { +func (in *ApplicationCredentialList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -617,7 +521,7 @@ func (in *FlavorList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlavorResourceSpec) DeepCopyInto(out *FlavorResourceSpec) { +func (in *ApplicationCredentialResourceSpec) DeepCopyInto(out *ApplicationCredentialResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name @@ -629,79 +533,113 @@ func (in *FlavorResourceSpec) DeepCopyInto(out *FlavorResourceSpec) { *out = new(string) **out = **in } - if in.IsPublic != nil { - in, out := &in.IsPublic, &out.IsPublic + if in.Unrestricted != nil { + in, out := &in.Unrestricted, &out.Unrestricted *out = new(bool) **out = **in } + if in.RoleRefs != nil { + in, out := &in.RoleRefs, &out.RoleRefs + *out = make([]KubernetesNameRef, len(*in)) + copy(*out, *in) + } + if in.AccessRules != nil { + in, out := &in.AccessRules, &out.AccessRules + *out = make([]ApplicationCredentialAccessRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ExpiresAt != nil { + in, out := &in.ExpiresAt, &out.ExpiresAt + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorResourceSpec. -func (in *FlavorResourceSpec) DeepCopy() *FlavorResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialResourceSpec. +func (in *ApplicationCredentialResourceSpec) DeepCopy() *ApplicationCredentialResourceSpec { if in == nil { return nil } - out := new(FlavorResourceSpec) + out := new(ApplicationCredentialResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlavorResourceStatus) DeepCopyInto(out *FlavorResourceStatus) { +func (in *ApplicationCredentialResourceStatus) DeepCopyInto(out *ApplicationCredentialResourceStatus) { *out = *in - if in.RAM != nil { - in, out := &in.RAM, &out.RAM - *out = new(int32) - **out = **in + if in.Roles != nil { + in, out := &in.Roles, &out.Roles + *out = make([]ApplicationCredentialRoleStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - if in.Vcpus != nil { - in, out := &in.Vcpus, &out.Vcpus - *out = new(int32) - **out = **in + if in.ExpiresAt != nil { + in, out := &in.ExpiresAt, &out.ExpiresAt + *out = (*in).DeepCopy() } - if in.Disk != nil { - in, out := &in.Disk, &out.Disk - *out = new(int32) - **out = **in + if in.AccessRules != nil { + in, out := &in.AccessRules, &out.AccessRules + *out = make([]ApplicationCredentialAccessRuleStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } - if in.Swap != nil { - in, out := &in.Swap, &out.Swap - *out = new(int32) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialResourceStatus. +func (in *ApplicationCredentialResourceStatus) DeepCopy() *ApplicationCredentialResourceStatus { + if in == nil { + return nil + } + out := new(ApplicationCredentialResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationCredentialRoleStatus) DeepCopyInto(out *ApplicationCredentialRoleStatus) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) **out = **in } - if in.IsPublic != nil { - in, out := &in.IsPublic, &out.IsPublic - *out = new(bool) + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) **out = **in } - if in.Ephemeral != nil { - in, out := &in.Ephemeral, &out.Ephemeral - *out = new(int32) + if in.DomainID != nil { + in, out := &in.DomainID, &out.DomainID + *out = new(string) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorResourceStatus. -func (in *FlavorResourceStatus) DeepCopy() *FlavorResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialRoleStatus. +func (in *ApplicationCredentialRoleStatus) DeepCopy() *ApplicationCredentialRoleStatus { if in == nil { return nil } - out := new(FlavorResourceStatus) + out := new(ApplicationCredentialRoleStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlavorSpec) DeepCopyInto(out *FlavorSpec) { +func (in *ApplicationCredentialSpec) DeepCopyInto(out *ApplicationCredentialSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(FlavorImport) + *out = new(ApplicationCredentialImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(FlavorResourceSpec) + *out = new(ApplicationCredentialResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -709,21 +647,26 @@ func (in *FlavorSpec) DeepCopyInto(out *FlavorSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorSpec. -func (in *FlavorSpec) DeepCopy() *FlavorSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialSpec. +func (in *ApplicationCredentialSpec) DeepCopy() *ApplicationCredentialSpec { if in == nil { return nil } - out := new(FlavorSpec) + out := new(ApplicationCredentialSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FlavorStatus) DeepCopyInto(out *FlavorStatus) { +func (in *ApplicationCredentialStatus) DeepCopyInto(out *ApplicationCredentialStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -739,23 +682,42 @@ func (in *FlavorStatus) DeepCopyInto(out *FlavorStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(FlavorResourceStatus) + *out = new(ApplicationCredentialResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorStatus. -func (in *FlavorStatus) DeepCopy() *FlavorStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCredentialStatus. +func (in *ApplicationCredentialStatus) DeepCopy() *ApplicationCredentialStatus { if in == nil { return nil } - out := new(FlavorStatus) + out := new(ApplicationCredentialStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIP) DeepCopyInto(out *FloatingIP) { +func (in *CloudCredentialsReference) DeepCopyInto(out *CloudCredentialsReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudCredentialsReference. +func (in *CloudCredentialsReference) DeepCopy() *CloudCredentialsReference { + if in == nil { + return nil + } + out := new(CloudCredentialsReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Domain) DeepCopyInto(out *Domain) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -763,18 +725,18 @@ func (in *FloatingIP) DeepCopyInto(out *FloatingIP) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIP. -func (in *FloatingIP) DeepCopy() *FloatingIP { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Domain. +func (in *Domain) DeepCopy() *Domain { if in == nil { return nil } - out := new(FloatingIP) + out := new(Domain) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FloatingIP) DeepCopyObject() runtime.Object { +func (in *Domain) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -782,48 +744,32 @@ func (in *FloatingIP) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIPFilter) DeepCopyInto(out *FloatingIPFilter) { +func (in *DomainFilter) DeepCopyInto(out *DomainFilter) { *out = *in - if in.FloatingIP != nil { - in, out := &in.FloatingIP, &out.FloatingIP - *out = new(IPvAny) - **out = **in - } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(NeutronDescription) - **out = **in - } - if in.FloatingNetworkRef != nil { - in, out := &in.FloatingNetworkRef, &out.FloatingNetworkRef - *out = new(KubernetesNameRef) - **out = **in - } - if in.PortRef != nil { - in, out := &in.PortRef, &out.PortRef - *out = new(KubernetesNameRef) + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(KeystoneName) **out = **in } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef - *out = new(KubernetesNameRef) + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) **out = **in } - in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPFilter. -func (in *FloatingIPFilter) DeepCopy() *FloatingIPFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainFilter. +func (in *DomainFilter) DeepCopy() *DomainFilter { if in == nil { return nil } - out := new(FloatingIPFilter) + out := new(DomainFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIPImport) DeepCopyInto(out *FloatingIPImport) { +func (in *DomainImport) DeepCopyInto(out *DomainImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -832,47 +778,47 @@ func (in *FloatingIPImport) DeepCopyInto(out *FloatingIPImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(FloatingIPFilter) + *out = new(DomainFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPImport. -func (in *FloatingIPImport) DeepCopy() *FloatingIPImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainImport. +func (in *DomainImport) DeepCopy() *DomainImport { if in == nil { return nil } - out := new(FloatingIPImport) + out := new(DomainImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIPList) DeepCopyInto(out *FloatingIPList) { +func (in *DomainList) DeepCopyInto(out *DomainList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]FloatingIP, len(*in)) + *out = make([]Domain, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPList. -func (in *FloatingIPList) DeepCopy() *FloatingIPList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainList. +func (in *DomainList) DeepCopy() *DomainList { if in == nil { return nil } - out := new(FloatingIPList) + out := new(DomainList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FloatingIPList) DeepCopyObject() runtime.Object { +func (in *DomainList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -880,92 +826,66 @@ func (in *FloatingIPList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIPResourceSpec) DeepCopyInto(out *FloatingIPResourceSpec) { +func (in *DomainResourceSpec) DeepCopyInto(out *DomainResourceSpec) { *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(KeystoneName) + **out = **in + } if in.Description != nil { in, out := &in.Description, &out.Description - *out = new(NeutronDescription) + *out = new(string) **out = **in } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } - if in.FloatingNetworkRef != nil { - in, out := &in.FloatingNetworkRef, &out.FloatingNetworkRef - *out = new(KubernetesNameRef) - **out = **in - } - if in.FloatingSubnetRef != nil { - in, out := &in.FloatingSubnetRef, &out.FloatingSubnetRef - *out = new(KubernetesNameRef) - **out = **in - } - if in.FloatingIP != nil { - in, out := &in.FloatingIP, &out.FloatingIP - *out = new(IPvAny) - **out = **in - } - if in.PortRef != nil { - in, out := &in.PortRef, &out.PortRef - *out = new(KubernetesNameRef) - **out = **in - } - if in.FixedIP != nil { - in, out := &in.FixedIP, &out.FixedIP - *out = new(IPvAny) - **out = **in - } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef - *out = new(KubernetesNameRef) + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPResourceSpec. -func (in *FloatingIPResourceSpec) DeepCopy() *FloatingIPResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainResourceSpec. +func (in *DomainResourceSpec) DeepCopy() *DomainResourceSpec { if in == nil { return nil } - out := new(FloatingIPResourceSpec) + out := new(DomainResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIPResourceStatus) DeepCopyInto(out *FloatingIPResourceStatus) { +func (in *DomainResourceStatus) DeepCopyInto(out *DomainResourceStatus) { *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in } - in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPResourceStatus. -func (in *FloatingIPResourceStatus) DeepCopy() *FloatingIPResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainResourceStatus. +func (in *DomainResourceStatus) DeepCopy() *DomainResourceStatus { if in == nil { return nil } - out := new(FloatingIPResourceStatus) + out := new(DomainResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIPSpec) DeepCopyInto(out *FloatingIPSpec) { +func (in *DomainSpec) DeepCopyInto(out *DomainSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(FloatingIPImport) + *out = new(DomainImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(FloatingIPResourceSpec) + *out = new(DomainResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -973,21 +893,26 @@ func (in *FloatingIPSpec) DeepCopyInto(out *FloatingIPSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPSpec. -func (in *FloatingIPSpec) DeepCopy() *FloatingIPSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainSpec. +func (in *DomainSpec) DeepCopy() *DomainSpec { if in == nil { return nil } - out := new(FloatingIPSpec) + out := new(DomainSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FloatingIPStatus) DeepCopyInto(out *FloatingIPStatus) { +func (in *DomainStatus) DeepCopyInto(out *DomainStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -1003,23 +928,27 @@ func (in *FloatingIPStatus) DeepCopyInto(out *FloatingIPStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(FloatingIPResourceStatus) + *out = new(DomainResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPStatus. -func (in *FloatingIPStatus) DeepCopy() *FloatingIPStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainStatus. +func (in *DomainStatus) DeepCopy() *DomainStatus { if in == nil { return nil } - out := new(FloatingIPStatus) + out := new(DomainStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Group) DeepCopyInto(out *Group) { +func (in *Endpoint) DeepCopyInto(out *Endpoint) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -1027,18 +956,18 @@ func (in *Group) DeepCopyInto(out *Group) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Group. -func (in *Group) DeepCopy() *Group { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint. +func (in *Endpoint) DeepCopy() *Endpoint { if in == nil { return nil } - out := new(Group) + out := new(Endpoint) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Group) DeepCopyObject() runtime.Object { +func (in *Endpoint) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1046,32 +975,27 @@ func (in *Group) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GroupFilter) DeepCopyInto(out *GroupFilter) { +func (in *EndpointFilter) DeepCopyInto(out *EndpointFilter) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(KeystoneName) - **out = **in - } - if in.DomainRef != nil { - in, out := &in.DomainRef, &out.DomainRef + if in.ServiceRef != nil { + in, out := &in.ServiceRef, &out.ServiceRef *out = new(KubernetesNameRef) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupFilter. -func (in *GroupFilter) DeepCopy() *GroupFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointFilter. +func (in *EndpointFilter) DeepCopy() *EndpointFilter { if in == nil { return nil } - out := new(GroupFilter) + out := new(EndpointFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GroupImport) DeepCopyInto(out *GroupImport) { +func (in *EndpointImport) DeepCopyInto(out *EndpointImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -1080,47 +1004,47 @@ func (in *GroupImport) DeepCopyInto(out *GroupImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(GroupFilter) + *out = new(EndpointFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupImport. -func (in *GroupImport) DeepCopy() *GroupImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointImport. +func (in *EndpointImport) DeepCopy() *EndpointImport { if in == nil { return nil } - out := new(GroupImport) + out := new(EndpointImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GroupList) DeepCopyInto(out *GroupList) { +func (in *EndpointList) DeepCopyInto(out *EndpointList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Group, len(*in)) + *out = make([]Endpoint, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupList. -func (in *GroupList) DeepCopy() *GroupList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointList. +func (in *EndpointList) DeepCopy() *EndpointList { if in == nil { return nil } - out := new(GroupList) + out := new(EndpointList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *GroupList) DeepCopyObject() runtime.Object { +func (in *EndpointList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1128,61 +1052,61 @@ func (in *GroupList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GroupResourceSpec) DeepCopyInto(out *GroupResourceSpec) { +func (in *EndpointResourceSpec) DeepCopyInto(out *EndpointResourceSpec) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(KeystoneName) - **out = **in - } if in.Description != nil { in, out := &in.Description, &out.Description *out = new(string) **out = **in } - if in.DomainRef != nil { - in, out := &in.DomainRef, &out.DomainRef - *out = new(KubernetesNameRef) + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupResourceSpec. -func (in *GroupResourceSpec) DeepCopy() *GroupResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointResourceSpec. +func (in *EndpointResourceSpec) DeepCopy() *EndpointResourceSpec { if in == nil { return nil } - out := new(GroupResourceSpec) + out := new(EndpointResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GroupResourceStatus) DeepCopyInto(out *GroupResourceStatus) { +func (in *EndpointResourceStatus) DeepCopyInto(out *EndpointResourceStatus) { *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupResourceStatus. -func (in *GroupResourceStatus) DeepCopy() *GroupResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointResourceStatus. +func (in *EndpointResourceStatus) DeepCopy() *EndpointResourceStatus { if in == nil { return nil } - out := new(GroupResourceStatus) + out := new(EndpointResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GroupSpec) DeepCopyInto(out *GroupSpec) { +func (in *EndpointSpec) DeepCopyInto(out *EndpointSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(GroupImport) + *out = new(EndpointImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(GroupResourceSpec) + *out = new(EndpointResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -1190,21 +1114,26 @@ func (in *GroupSpec) DeepCopyInto(out *GroupSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupSpec. -func (in *GroupSpec) DeepCopy() *GroupSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointSpec. +func (in *EndpointSpec) DeepCopy() *EndpointSpec { if in == nil { return nil } - out := new(GroupSpec) + out := new(EndpointSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GroupStatus) DeepCopyInto(out *GroupStatus) { +func (in *EndpointStatus) DeepCopyInto(out *EndpointStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -1220,195 +1149,269 @@ func (in *GroupStatus) DeepCopyInto(out *GroupStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(GroupResourceStatus) - **out = **in + *out = new(EndpointResourceStatus) + (*in).DeepCopyInto(*out) + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupStatus. -func (in *GroupStatus) DeepCopy() *GroupStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointStatus. +func (in *EndpointStatus) DeepCopy() *EndpointStatus { if in == nil { return nil } - out := new(GroupStatus) + out := new(EndpointStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HostRoute) DeepCopyInto(out *HostRoute) { +func (in *ExternalGateway) DeepCopyInto(out *ExternalGateway) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostRoute. -func (in *HostRoute) DeepCopy() *HostRoute { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalGateway. +func (in *ExternalGateway) DeepCopy() *ExternalGateway { if in == nil { return nil } - out := new(HostRoute) + out := new(ExternalGateway) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *HostRouteStatus) DeepCopyInto(out *HostRouteStatus) { +func (in *ExternalGatewayStatus) DeepCopyInto(out *ExternalGatewayStatus) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostRouteStatus. -func (in *HostRouteStatus) DeepCopy() *HostRouteStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalGatewayStatus. +func (in *ExternalGatewayStatus) DeepCopy() *ExternalGatewayStatus { if in == nil { return nil } - out := new(HostRouteStatus) + out := new(ExternalGatewayStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IPv6Options) DeepCopyInto(out *IPv6Options) { +func (in *FilterByKeystoneTags) DeepCopyInto(out *FilterByKeystoneTags) { *out = *in - if in.AddressMode != nil { - in, out := &in.AddressMode, &out.AddressMode - *out = new(IPv6AddressMode) - **out = **in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]KeystoneTag, len(*in)) + copy(*out, *in) } - if in.RAMode != nil { - in, out := &in.RAMode, &out.RAMode - *out = new(IPv6RAMode) - **out = **in + if in.TagsAny != nil { + in, out := &in.TagsAny, &out.TagsAny + *out = make([]KeystoneTag, len(*in)) + copy(*out, *in) + } + if in.NotTags != nil { + in, out := &in.NotTags, &out.NotTags + *out = make([]KeystoneTag, len(*in)) + copy(*out, *in) + } + if in.NotTagsAny != nil { + in, out := &in.NotTagsAny, &out.NotTagsAny + *out = make([]KeystoneTag, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPv6Options. -func (in *IPv6Options) DeepCopy() *IPv6Options { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterByKeystoneTags. +func (in *FilterByKeystoneTags) DeepCopy() *FilterByKeystoneTags { if in == nil { return nil } - out := new(IPv6Options) + out := new(FilterByKeystoneTags) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Image) DeepCopyInto(out *Image) { +func (in *FilterByNeutronTags) DeepCopyInto(out *FilterByNeutronTags) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image. -func (in *Image) DeepCopy() *Image { - if in == nil { - return nil + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) } - out := new(Image) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Image) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c + if in.TagsAny != nil { + in, out := &in.TagsAny, &out.TagsAny + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageContent) DeepCopyInto(out *ImageContent) { - *out = *in - if in.Download != nil { - in, out := &in.Download, &out.Download - *out = new(ImageContentSourceDownload) - (*in).DeepCopyInto(*out) + if in.NotTags != nil { + in, out := &in.NotTags, &out.NotTags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) + } + if in.NotTagsAny != nil { + in, out := &in.NotTagsAny, &out.NotTagsAny + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageContent. -func (in *ImageContent) DeepCopy() *ImageContent { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterByNeutronTags. +func (in *FilterByNeutronTags) DeepCopy() *FilterByNeutronTags { if in == nil { return nil } - out := new(ImageContent) + out := new(FilterByNeutronTags) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageContentSourceDownload) DeepCopyInto(out *ImageContentSourceDownload) { +func (in *FilterByServerTags) DeepCopyInto(out *FilterByServerTags) { *out = *in - if in.Decompress != nil { - in, out := &in.Decompress, &out.Decompress - *out = new(ImageCompression) - **out = **in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]ServerTag, len(*in)) + copy(*out, *in) } - if in.Hash != nil { - in, out := &in.Hash, &out.Hash - *out = new(ImageHash) - **out = **in + if in.TagsAny != nil { + in, out := &in.TagsAny, &out.TagsAny + *out = make([]ServerTag, len(*in)) + copy(*out, *in) + } + if in.NotTags != nil { + in, out := &in.NotTags, &out.NotTags + *out = make([]ServerTag, len(*in)) + copy(*out, *in) + } + if in.NotTagsAny != nil { + in, out := &in.NotTagsAny, &out.NotTagsAny + *out = make([]ServerTag, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageContentSourceDownload. -func (in *ImageContentSourceDownload) DeepCopy() *ImageContentSourceDownload { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FilterByServerTags. +func (in *FilterByServerTags) DeepCopy() *FilterByServerTags { if in == nil { return nil } - out := new(ImageContentSourceDownload) + out := new(FilterByServerTags) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageFilter) DeepCopyInto(out *ImageFilter) { +func (in *FixedIPStatus) DeepCopyInto(out *FixedIPStatus) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FixedIPStatus. +func (in *FixedIPStatus) DeepCopy() *FixedIPStatus { + if in == nil { + return nil } - if in.Visibility != nil { - in, out := &in.Visibility, &out.Visibility - *out = new(ImageVisibility) - **out = **in + out := new(FixedIPStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Flavor) DeepCopyInto(out *Flavor) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Flavor. +func (in *Flavor) DeepCopy() *Flavor { + if in == nil { + return nil } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]ImageTag, len(*in)) - copy(*out, *in) + out := new(Flavor) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Flavor) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c } + return nil } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageFilter. -func (in *ImageFilter) DeepCopy() *ImageFilter { +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlavorExtraSpec) DeepCopyInto(out *FlavorExtraSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorExtraSpec. +func (in *FlavorExtraSpec) DeepCopy() *FlavorExtraSpec { if in == nil { return nil } - out := new(ImageFilter) + out := new(FlavorExtraSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageHash) DeepCopyInto(out *ImageHash) { +func (in *FlavorExtraSpecStatus) DeepCopyInto(out *FlavorExtraSpecStatus) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageHash. -func (in *ImageHash) DeepCopy() *ImageHash { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorExtraSpecStatus. +func (in *FlavorExtraSpecStatus) DeepCopy() *FlavorExtraSpecStatus { if in == nil { return nil } - out := new(ImageHash) + out := new(FlavorExtraSpecStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageImport) DeepCopyInto(out *ImageImport) { +func (in *FlavorFilter) DeepCopyInto(out *FlavorFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.RAM != nil { + in, out := &in.RAM, &out.RAM + *out = new(int32) + **out = **in + } + if in.Vcpus != nil { + in, out := &in.Vcpus, &out.Vcpus + *out = new(int32) + **out = **in + } + if in.Disk != nil { + in, out := &in.Disk, &out.Disk + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorFilter. +func (in *FlavorFilter) DeepCopy() *FlavorFilter { + if in == nil { + return nil + } + out := new(FlavorFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlavorImport) DeepCopyInto(out *FlavorImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -1417,47 +1420,47 @@ func (in *ImageImport) DeepCopyInto(out *ImageImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(ImageFilter) + *out = new(FlavorFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageImport. -func (in *ImageImport) DeepCopy() *ImageImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorImport. +func (in *FlavorImport) DeepCopy() *FlavorImport { if in == nil { return nil } - out := new(ImageImport) + out := new(FlavorImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageList) DeepCopyInto(out *ImageList) { +func (in *FlavorList) DeepCopyInto(out *FlavorList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Image, len(*in)) + *out = make([]Flavor, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageList. -func (in *ImageList) DeepCopy() *ImageList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorList. +func (in *FlavorList) DeepCopy() *FlavorList { if in == nil { return nil } - out := new(ImageList) + out := new(FlavorList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ImageList) DeepCopyObject() runtime.Object { +func (in *FlavorList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1465,206 +1468,2335 @@ func (in *ImageList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageProperties) DeepCopyInto(out *ImageProperties) { +func (in *FlavorResourceSpec) DeepCopyInto(out *FlavorResourceSpec) { *out = *in - if in.Architecture != nil { - in, out := &in.Architecture, &out.Architecture - *out = new(string) + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) **out = **in } - if in.HypervisorType != nil { - in, out := &in.HypervisorType, &out.HypervisorType + if in.Description != nil { + in, out := &in.Description, &out.Description *out = new(string) **out = **in } - if in.MinDiskGB != nil { - in, out := &in.MinDiskGB, &out.MinDiskGB - *out = new(int32) - **out = **in + if in.ExtraSpecs != nil { + in, out := &in.ExtraSpecs, &out.ExtraSpecs + *out = make([]FlavorExtraSpec, len(*in)) + copy(*out, *in) } - if in.MinMemoryMB != nil { - in, out := &in.MinMemoryMB, &out.MinMemoryMB - *out = new(int32) + if in.IsPublic != nil { + in, out := &in.IsPublic, &out.IsPublic + *out = new(bool) **out = **in } - if in.Hardware != nil { - in, out := &in.Hardware, &out.Hardware - *out = new(ImagePropertiesHardware) - (*in).DeepCopyInto(*out) - } - if in.OperatingSystem != nil { - in, out := &in.OperatingSystem, &out.OperatingSystem - *out = new(ImagePropertiesOperatingSystem) - (*in).DeepCopyInto(*out) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageProperties. -func (in *ImageProperties) DeepCopy() *ImageProperties { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorResourceSpec. +func (in *FlavorResourceSpec) DeepCopy() *FlavorResourceSpec { if in == nil { return nil } - out := new(ImageProperties) + out := new(FlavorResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImagePropertiesHardware) DeepCopyInto(out *ImagePropertiesHardware) { +func (in *FlavorResourceStatus) DeepCopyInto(out *FlavorResourceStatus) { *out = *in - if in.CPUSockets != nil { - in, out := &in.CPUSockets, &out.CPUSockets + if in.RAM != nil { + in, out := &in.RAM, &out.RAM *out = new(int32) **out = **in } - if in.CPUCores != nil { - in, out := &in.CPUCores, &out.CPUCores + if in.Vcpus != nil { + in, out := &in.Vcpus, &out.Vcpus *out = new(int32) **out = **in } - if in.CPUThreads != nil { - in, out := &in.CPUThreads, &out.CPUThreads + if in.Disk != nil { + in, out := &in.Disk, &out.Disk *out = new(int32) **out = **in } - if in.CPUPolicy != nil { - in, out := &in.CPUPolicy, &out.CPUPolicy - *out = new(string) + if in.Swap != nil { + in, out := &in.Swap, &out.Swap + *out = new(int32) **out = **in } - if in.CPUThreadPolicy != nil { - in, out := &in.CPUThreadPolicy, &out.CPUThreadPolicy - *out = new(string) + if in.ExtraSpecs != nil { + in, out := &in.ExtraSpecs, &out.ExtraSpecs + *out = make([]FlavorExtraSpecStatus, len(*in)) + copy(*out, *in) + } + if in.IsPublic != nil { + in, out := &in.IsPublic, &out.IsPublic + *out = new(bool) **out = **in } - if in.CDROMBus != nil { - in, out := &in.CDROMBus, &out.CDROMBus - *out = new(ImageHWBus) + if in.Ephemeral != nil { + in, out := &in.Ephemeral, &out.Ephemeral + *out = new(int32) **out = **in } - if in.DiskBus != nil { - in, out := &in.DiskBus, &out.DiskBus - *out = new(ImageHWBus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorResourceStatus. +func (in *FlavorResourceStatus) DeepCopy() *FlavorResourceStatus { + if in == nil { + return nil + } + out := new(FlavorResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlavorSpec) DeepCopyInto(out *FlavorSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(FlavorImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(FlavorResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorSpec. +func (in *FlavorSpec) DeepCopy() *FlavorSpec { + if in == nil { + return nil + } + out := new(FlavorSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlavorStatus) DeepCopyInto(out *FlavorStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(FlavorResourceStatus) + (*in).DeepCopyInto(*out) + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlavorStatus. +func (in *FlavorStatus) DeepCopy() *FlavorStatus { + if in == nil { + return nil + } + out := new(FlavorStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIP) DeepCopyInto(out *FloatingIP) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIP. +func (in *FloatingIP) DeepCopy() *FloatingIP { + if in == nil { + return nil + } + out := new(FloatingIP) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FloatingIP) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIPFilter) DeepCopyInto(out *FloatingIPFilter) { + *out = *in + if in.FloatingIP != nil { + in, out := &in.FloatingIP, &out.FloatingIP + *out = new(IPvAny) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.FloatingNetworkRef != nil { + in, out := &in.FloatingNetworkRef, &out.FloatingNetworkRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.PortRef != nil { + in, out := &in.PortRef, &out.PortRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPFilter. +func (in *FloatingIPFilter) DeepCopy() *FloatingIPFilter { + if in == nil { + return nil + } + out := new(FloatingIPFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIPImport) DeepCopyInto(out *FloatingIPImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(FloatingIPFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPImport. +func (in *FloatingIPImport) DeepCopy() *FloatingIPImport { + if in == nil { + return nil + } + out := new(FloatingIPImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIPList) DeepCopyInto(out *FloatingIPList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FloatingIP, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPList. +func (in *FloatingIPList) DeepCopy() *FloatingIPList { + if in == nil { + return nil + } + out := new(FloatingIPList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FloatingIPList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIPResourceSpec) DeepCopyInto(out *FloatingIPResourceSpec) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) + } + if in.FloatingNetworkRef != nil { + in, out := &in.FloatingNetworkRef, &out.FloatingNetworkRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.FloatingSubnetRef != nil { + in, out := &in.FloatingSubnetRef, &out.FloatingSubnetRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.FloatingIP != nil { + in, out := &in.FloatingIP, &out.FloatingIP + *out = new(IPvAny) + **out = **in + } + if in.PortRef != nil { + in, out := &in.PortRef, &out.PortRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.FixedIP != nil { + in, out := &in.FixedIP, &out.FixedIP + *out = new(IPvAny) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPResourceSpec. +func (in *FloatingIPResourceSpec) DeepCopy() *FloatingIPResourceSpec { + if in == nil { + return nil + } + out := new(FloatingIPResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIPResourceStatus) DeepCopyInto(out *FloatingIPResourceStatus) { + *out = *in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPResourceStatus. +func (in *FloatingIPResourceStatus) DeepCopy() *FloatingIPResourceStatus { + if in == nil { + return nil + } + out := new(FloatingIPResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIPSpec) DeepCopyInto(out *FloatingIPSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(FloatingIPImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(FloatingIPResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPSpec. +func (in *FloatingIPSpec) DeepCopy() *FloatingIPSpec { + if in == nil { + return nil + } + out := new(FloatingIPSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FloatingIPStatus) DeepCopyInto(out *FloatingIPStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(FloatingIPResourceStatus) + (*in).DeepCopyInto(*out) + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FloatingIPStatus. +func (in *FloatingIPStatus) DeepCopy() *FloatingIPStatus { + if in == nil { + return nil + } + out := new(FloatingIPStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Group) DeepCopyInto(out *Group) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Group. +func (in *Group) DeepCopy() *Group { + if in == nil { + return nil + } + out := new(Group) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Group) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupFilter) DeepCopyInto(out *GroupFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(KeystoneName) + **out = **in + } + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupFilter. +func (in *GroupFilter) DeepCopy() *GroupFilter { + if in == nil { + return nil + } + out := new(GroupFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupImport) DeepCopyInto(out *GroupImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(GroupFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupImport. +func (in *GroupImport) DeepCopy() *GroupImport { + if in == nil { + return nil + } + out := new(GroupImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupList) DeepCopyInto(out *GroupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Group, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupList. +func (in *GroupList) DeepCopy() *GroupList { + if in == nil { + return nil + } + out := new(GroupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GroupList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupResourceSpec) DeepCopyInto(out *GroupResourceSpec) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(KeystoneName) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupResourceSpec. +func (in *GroupResourceSpec) DeepCopy() *GroupResourceSpec { + if in == nil { + return nil + } + out := new(GroupResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupResourceStatus) DeepCopyInto(out *GroupResourceStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupResourceStatus. +func (in *GroupResourceStatus) DeepCopy() *GroupResourceStatus { + if in == nil { + return nil + } + out := new(GroupResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupSpec) DeepCopyInto(out *GroupSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(GroupImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(GroupResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupSpec. +func (in *GroupSpec) DeepCopy() *GroupSpec { + if in == nil { + return nil + } + out := new(GroupSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GroupStatus) DeepCopyInto(out *GroupStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(GroupResourceStatus) + **out = **in + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupStatus. +func (in *GroupStatus) DeepCopy() *GroupStatus { + if in == nil { + return nil + } + out := new(GroupStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostID) DeepCopyInto(out *HostID) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostID. +func (in *HostID) DeepCopy() *HostID { + if in == nil { + return nil + } + out := new(HostID) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostRoute) DeepCopyInto(out *HostRoute) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostRoute. +func (in *HostRoute) DeepCopy() *HostRoute { + if in == nil { + return nil + } + out := new(HostRoute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostRouteStatus) DeepCopyInto(out *HostRouteStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostRouteStatus. +func (in *HostRouteStatus) DeepCopy() *HostRouteStatus { + if in == nil { + return nil + } + out := new(HostRouteStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPv6Options) DeepCopyInto(out *IPv6Options) { + *out = *in + if in.AddressMode != nil { + in, out := &in.AddressMode, &out.AddressMode + *out = new(IPv6AddressMode) + **out = **in + } + if in.RAMode != nil { + in, out := &in.RAMode, &out.RAMode + *out = new(IPv6RAMode) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPv6Options. +func (in *IPv6Options) DeepCopy() *IPv6Options { + if in == nil { + return nil + } + out := new(IPv6Options) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Image) DeepCopyInto(out *Image) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image. +func (in *Image) DeepCopy() *Image { + if in == nil { + return nil + } + out := new(Image) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Image) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageContent) DeepCopyInto(out *ImageContent) { + *out = *in + if in.Download != nil { + in, out := &in.Download, &out.Download + *out = new(ImageContentSourceDownload) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageContent. +func (in *ImageContent) DeepCopy() *ImageContent { + if in == nil { + return nil + } + out := new(ImageContent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageContentSourceDownload) DeepCopyInto(out *ImageContentSourceDownload) { + *out = *in + if in.Decompress != nil { + in, out := &in.Decompress, &out.Decompress + *out = new(ImageCompression) + **out = **in + } + if in.Hash != nil { + in, out := &in.Hash, &out.Hash + *out = new(ImageHash) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageContentSourceDownload. +func (in *ImageContentSourceDownload) DeepCopy() *ImageContentSourceDownload { + if in == nil { + return nil + } + out := new(ImageContentSourceDownload) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageFilter) DeepCopyInto(out *ImageFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Visibility != nil { + in, out := &in.Visibility, &out.Visibility + *out = new(ImageVisibility) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]ImageTag, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageFilter. +func (in *ImageFilter) DeepCopy() *ImageFilter { + if in == nil { + return nil + } + out := new(ImageFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageHash) DeepCopyInto(out *ImageHash) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageHash. +func (in *ImageHash) DeepCopy() *ImageHash { + if in == nil { + return nil + } + out := new(ImageHash) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageImport) DeepCopyInto(out *ImageImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(ImageFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageImport. +func (in *ImageImport) DeepCopy() *ImageImport { + if in == nil { + return nil + } + out := new(ImageImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageList) DeepCopyInto(out *ImageList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Image, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageList. +func (in *ImageList) DeepCopy() *ImageList { + if in == nil { + return nil + } + out := new(ImageList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ImageList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageProperties) DeepCopyInto(out *ImageProperties) { + *out = *in + if in.Architecture != nil { + in, out := &in.Architecture, &out.Architecture + *out = new(string) + **out = **in + } + if in.HypervisorType != nil { + in, out := &in.HypervisorType, &out.HypervisorType + *out = new(string) + **out = **in + } + if in.MinDiskGB != nil { + in, out := &in.MinDiskGB, &out.MinDiskGB + *out = new(int32) + **out = **in + } + if in.MinMemoryMB != nil { + in, out := &in.MinMemoryMB, &out.MinMemoryMB + *out = new(int32) + **out = **in + } + if in.Hardware != nil { + in, out := &in.Hardware, &out.Hardware + *out = new(ImagePropertiesHardware) + (*in).DeepCopyInto(*out) + } + if in.OperatingSystem != nil { + in, out := &in.OperatingSystem, &out.OperatingSystem + *out = new(ImagePropertiesOperatingSystem) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageProperties. +func (in *ImageProperties) DeepCopy() *ImageProperties { + if in == nil { + return nil + } + out := new(ImageProperties) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImagePropertiesHardware) DeepCopyInto(out *ImagePropertiesHardware) { + *out = *in + if in.CPUSockets != nil { + in, out := &in.CPUSockets, &out.CPUSockets + *out = new(int32) + **out = **in + } + if in.CPUCores != nil { + in, out := &in.CPUCores, &out.CPUCores + *out = new(int32) + **out = **in + } + if in.CPUThreads != nil { + in, out := &in.CPUThreads, &out.CPUThreads + *out = new(int32) + **out = **in + } + if in.CPUPolicy != nil { + in, out := &in.CPUPolicy, &out.CPUPolicy + *out = new(string) + **out = **in + } + if in.CPUThreadPolicy != nil { + in, out := &in.CPUThreadPolicy, &out.CPUThreadPolicy + *out = new(string) + **out = **in + } + if in.CDROMBus != nil { + in, out := &in.CDROMBus, &out.CDROMBus + *out = new(ImageHWBus) + **out = **in + } + if in.DiskBus != nil { + in, out := &in.DiskBus, &out.DiskBus + *out = new(ImageHWBus) + **out = **in + } + if in.SCSIModel != nil { + in, out := &in.SCSIModel, &out.SCSIModel + *out = new(string) + **out = **in + } + if in.VIFModel != nil { + in, out := &in.VIFModel, &out.VIFModel + *out = new(string) + **out = **in + } + if in.RngModel != nil { + in, out := &in.RngModel, &out.RngModel + *out = new(string) + **out = **in + } + if in.QemuGuestAgent != nil { + in, out := &in.QemuGuestAgent, &out.QemuGuestAgent + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePropertiesHardware. +func (in *ImagePropertiesHardware) DeepCopy() *ImagePropertiesHardware { + if in == nil { + return nil + } + out := new(ImagePropertiesHardware) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImagePropertiesOperatingSystem) DeepCopyInto(out *ImagePropertiesOperatingSystem) { + *out = *in + if in.Distro != nil { + in, out := &in.Distro, &out.Distro + *out = new(string) + **out = **in + } + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePropertiesOperatingSystem. +func (in *ImagePropertiesOperatingSystem) DeepCopy() *ImagePropertiesOperatingSystem { + if in == nil { + return nil + } + out := new(ImagePropertiesOperatingSystem) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageResourceSpec) DeepCopyInto(out *ImageResourceSpec) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Protected != nil { + in, out := &in.Protected, &out.Protected + *out = new(bool) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]ImageTag, len(*in)) + copy(*out, *in) + } + if in.Visibility != nil { + in, out := &in.Visibility, &out.Visibility + *out = new(ImageVisibility) + **out = **in + } + if in.Properties != nil { + in, out := &in.Properties, &out.Properties + *out = new(ImageProperties) + (*in).DeepCopyInto(*out) + } + if in.Content != nil { + in, out := &in.Content, &out.Content + *out = new(ImageContent) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageResourceSpec. +func (in *ImageResourceSpec) DeepCopy() *ImageResourceSpec { + if in == nil { + return nil + } + out := new(ImageResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageResourceStatus) DeepCopyInto(out *ImageResourceStatus) { + *out = *in + if in.Hash != nil { + in, out := &in.Hash, &out.Hash + *out = new(ImageHash) + **out = **in + } + if in.SizeB != nil { + in, out := &in.SizeB, &out.SizeB + *out = new(int64) + **out = **in + } + if in.VirtualSizeB != nil { + in, out := &in.VirtualSizeB, &out.VirtualSizeB + *out = new(int64) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageResourceStatus. +func (in *ImageResourceStatus) DeepCopy() *ImageResourceStatus { + if in == nil { + return nil + } + out := new(ImageResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageSpec) DeepCopyInto(out *ImageSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(ImageImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(ImageResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageSpec. +func (in *ImageSpec) DeepCopy() *ImageSpec { + if in == nil { + return nil + } + out := new(ImageSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageStatus) DeepCopyInto(out *ImageStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(ImageResourceStatus) + (*in).DeepCopyInto(*out) + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } + in.ImageStatusExtra.DeepCopyInto(&out.ImageStatusExtra) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatus. +func (in *ImageStatus) DeepCopy() *ImageStatus { + if in == nil { + return nil + } + out := new(ImageStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageStatusExtra) DeepCopyInto(out *ImageStatusExtra) { + *out = *in + if in.DownloadAttempts != nil { + in, out := &in.DownloadAttempts, &out.DownloadAttempts + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatusExtra. +func (in *ImageStatusExtra) DeepCopy() *ImageStatusExtra { + if in == nil { + return nil + } + out := new(ImageStatusExtra) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPair) DeepCopyInto(out *KeyPair) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPair. +func (in *KeyPair) DeepCopy() *KeyPair { + if in == nil { + return nil + } + out := new(KeyPair) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KeyPair) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPairFilter) DeepCopyInto(out *KeyPairFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairFilter. +func (in *KeyPairFilter) DeepCopy() *KeyPairFilter { + if in == nil { + return nil + } + out := new(KeyPairFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPairImport) DeepCopyInto(out *KeyPairImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(KeyPairFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairImport. +func (in *KeyPairImport) DeepCopy() *KeyPairImport { + if in == nil { + return nil + } + out := new(KeyPairImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPairList) DeepCopyInto(out *KeyPairList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]KeyPair, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairList. +func (in *KeyPairList) DeepCopy() *KeyPairList { + if in == nil { + return nil + } + out := new(KeyPairList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KeyPairList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPairResourceSpec) DeepCopyInto(out *KeyPairResourceSpec) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairResourceSpec. +func (in *KeyPairResourceSpec) DeepCopy() *KeyPairResourceSpec { + if in == nil { + return nil + } + out := new(KeyPairResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPairResourceStatus) DeepCopyInto(out *KeyPairResourceStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairResourceStatus. +func (in *KeyPairResourceStatus) DeepCopy() *KeyPairResourceStatus { + if in == nil { + return nil + } + out := new(KeyPairResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPairSpec) DeepCopyInto(out *KeyPairSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(KeyPairImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(KeyPairResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairSpec. +func (in *KeyPairSpec) DeepCopy() *KeyPairSpec { + if in == nil { + return nil + } + out := new(KeyPairSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyPairStatus) DeepCopyInto(out *KeyPairStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(KeyPairResourceStatus) + **out = **in + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairStatus. +func (in *KeyPairStatus) DeepCopy() *KeyPairStatus { + if in == nil { + return nil + } + out := new(KeyPairStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedOptions) DeepCopyInto(out *ManagedOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedOptions. +func (in *ManagedOptions) DeepCopy() *ManagedOptions { + if in == nil { + return nil + } + out := new(ManagedOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Network) DeepCopyInto(out *Network) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network. +func (in *Network) DeepCopy() *Network { + if in == nil { + return nil + } + out := new(Network) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Network) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkFilter) DeepCopyInto(out *NetworkFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.External != nil { + in, out := &in.External, &out.External + *out = new(bool) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkFilter. +func (in *NetworkFilter) DeepCopy() *NetworkFilter { + if in == nil { + return nil + } + out := new(NetworkFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkImport) DeepCopyInto(out *NetworkImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(NetworkFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkImport. +func (in *NetworkImport) DeepCopy() *NetworkImport { + if in == nil { + return nil + } + out := new(NetworkImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkList) DeepCopyInto(out *NetworkList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Network, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkList. +func (in *NetworkList) DeepCopy() *NetworkList { + if in == nil { + return nil + } + out := new(NetworkList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkResourceSpec) DeepCopyInto(out *NetworkResourceSpec) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) + } + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp + *out = new(bool) + **out = **in + } + if in.DNSDomain != nil { + in, out := &in.DNSDomain, &out.DNSDomain + *out = new(DNSDomain) + **out = **in + } + if in.MTU != nil { + in, out := &in.MTU, &out.MTU + *out = new(MTU) + **out = **in + } + if in.PortSecurityEnabled != nil { + in, out := &in.PortSecurityEnabled, &out.PortSecurityEnabled + *out = new(bool) + **out = **in + } + if in.External != nil { + in, out := &in.External, &out.External + *out = new(bool) + **out = **in + } + if in.Shared != nil { + in, out := &in.Shared, &out.Shared + *out = new(bool) + **out = **in + } + if in.AvailabilityZoneHints != nil { + in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints + *out = make([]AvailabilityZoneHint, len(*in)) + copy(*out, *in) + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkResourceSpec. +func (in *NetworkResourceSpec) DeepCopy() *NetworkResourceSpec { + if in == nil { + return nil + } + out := new(NetworkResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkResourceStatus) DeepCopyInto(out *NetworkResourceStatus) { + *out = *in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp + *out = new(bool) + **out = **in + } + if in.AvailabilityZoneHints != nil { + in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.MTU != nil { + in, out := &in.MTU, &out.MTU + *out = new(int32) + **out = **in + } + if in.PortSecurityEnabled != nil { + in, out := &in.PortSecurityEnabled, &out.PortSecurityEnabled + *out = new(bool) + **out = **in + } + if in.Provider != nil { + in, out := &in.Provider, &out.Provider + *out = new(ProviderPropertiesStatus) + (*in).DeepCopyInto(*out) + } + if in.External != nil { + in, out := &in.External, &out.External + *out = new(bool) + **out = **in + } + if in.Shared != nil { + in, out := &in.Shared, &out.Shared + *out = new(bool) + **out = **in + } + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkResourceStatus. +func (in *NetworkResourceStatus) DeepCopy() *NetworkResourceStatus { + if in == nil { + return nil + } + out := new(NetworkResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(NetworkImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(NetworkResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkSpec. +func (in *NetworkSpec) DeepCopy() *NetworkSpec { + if in == nil { + return nil + } + out := new(NetworkSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(NetworkResourceStatus) + (*in).DeepCopyInto(*out) + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkStatus. +func (in *NetworkStatus) DeepCopy() *NetworkStatus { + if in == nil { + return nil + } + out := new(NetworkStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NeutronStatusMetadata) DeepCopyInto(out *NeutronStatusMetadata) { + *out = *in + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.UpdatedAt != nil { + in, out := &in.UpdatedAt, &out.UpdatedAt + *out = (*in).DeepCopy() + } + if in.RevisionNumber != nil { + in, out := &in.RevisionNumber, &out.RevisionNumber + *out = new(int64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronStatusMetadata. +func (in *NeutronStatusMetadata) DeepCopy() *NeutronStatusMetadata { + if in == nil { + return nil + } + out := new(NeutronStatusMetadata) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Port) DeepCopyInto(out *Port) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Port. +func (in *Port) DeepCopy() *Port { + if in == nil { + return nil + } + out := new(Port) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Port) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortFilter) DeepCopyInto(out *PortFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp + *out = new(bool) + **out = **in + } + in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortFilter. +func (in *PortFilter) DeepCopy() *PortFilter { + if in == nil { + return nil + } + out := new(PortFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortImport) DeepCopyInto(out *PortImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(PortFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortImport. +func (in *PortImport) DeepCopy() *PortImport { + if in == nil { + return nil + } + out := new(PortImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortList) DeepCopyInto(out *PortList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Port, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortList. +func (in *PortList) DeepCopy() *PortList { + if in == nil { + return nil + } + out := new(PortList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PortList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortRangeSpec) DeepCopyInto(out *PortRangeSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortRangeSpec. +func (in *PortRangeSpec) DeepCopy() *PortRangeSpec { + if in == nil { + return nil + } + out := new(PortRangeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortRangeStatus) DeepCopyInto(out *PortRangeStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortRangeStatus. +func (in *PortRangeStatus) DeepCopy() *PortRangeStatus { + if in == nil { + return nil + } + out := new(PortRangeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortResourceSpec) DeepCopyInto(out *PortResourceSpec) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) + } + if in.AllowedAddressPairs != nil { + in, out := &in.AllowedAddressPairs, &out.AllowedAddressPairs + *out = make([]AllowedAddressPair, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Addresses != nil { + in, out := &in.Addresses, &out.Addresses + *out = make([]Address, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp + *out = new(bool) + **out = **in + } + if in.SecurityGroupRefs != nil { + in, out := &in.SecurityGroupRefs, &out.SecurityGroupRefs + *out = make([]KubernetesNameRef, len(*in)) + copy(*out, *in) + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.HostID != nil { + in, out := &in.HostID, &out.HostID + *out = new(HostID) + **out = **in + } + if in.TrustedVIF != nil { + in, out := &in.TrustedVIF, &out.TrustedVIF + *out = new(bool) + **out = **in + } + if in.ValueSpecs != nil { + in, out := &in.ValueSpecs, &out.ValueSpecs + *out = make([]PortValueSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.PropagateUplinkStatus != nil { + in, out := &in.PropagateUplinkStatus, &out.PropagateUplinkStatus + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortResourceSpec. +func (in *PortResourceSpec) DeepCopy() *PortResourceSpec { + if in == nil { + return nil + } + out := new(PortResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortResourceStatus) DeepCopyInto(out *PortResourceStatus) { + *out = *in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp + *out = new(bool) + **out = **in + } + if in.AllowedAddressPairs != nil { + in, out := &in.AllowedAddressPairs, &out.AllowedAddressPairs + *out = make([]AllowedAddressPairStatus, len(*in)) + copy(*out, *in) + } + if in.FixedIPs != nil { + in, out := &in.FixedIPs, &out.FixedIPs + *out = make([]FixedIPStatus, len(*in)) + copy(*out, *in) + } + if in.SecurityGroups != nil { + in, out := &in.SecurityGroups, &out.SecurityGroups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PropagateUplinkStatus != nil { + in, out := &in.PropagateUplinkStatus, &out.PropagateUplinkStatus + *out = new(bool) + **out = **in + } + if in.PortSecurityEnabled != nil { + in, out := &in.PortSecurityEnabled, &out.PortSecurityEnabled + *out = new(bool) + **out = **in + } + if in.TrustedVIF != nil { + in, out := &in.TrustedVIF, &out.TrustedVIF + *out = new(bool) + **out = **in + } + in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortResourceStatus. +func (in *PortResourceStatus) DeepCopy() *PortResourceStatus { + if in == nil { + return nil + } + out := new(PortResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortSpec) DeepCopyInto(out *PortSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(PortImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(PortResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortSpec. +func (in *PortSpec) DeepCopy() *PortSpec { + if in == nil { + return nil + } + out := new(PortSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortStatus) DeepCopyInto(out *PortStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(PortResourceStatus) + (*in).DeepCopyInto(*out) + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortStatus. +func (in *PortStatus) DeepCopy() *PortStatus { + if in == nil { + return nil + } + out := new(PortStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PortValueSpec) DeepCopyInto(out *PortValueSpec) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortValueSpec. +func (in *PortValueSpec) DeepCopy() *PortValueSpec { + if in == nil { + return nil + } + out := new(PortValueSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Project) DeepCopyInto(out *Project) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Project. +func (in *Project) DeepCopy() *Project { + if in == nil { + return nil + } + out := new(Project) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Project) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProjectFilter) DeepCopyInto(out *ProjectFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(KeystoneName) **out = **in } - if in.SCSIModel != nil { - in, out := &in.SCSIModel, &out.SCSIModel - *out = new(string) + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) **out = **in } - if in.VIFModel != nil { - in, out := &in.VIFModel, &out.VIFModel - *out = new(string) - **out = **in + in.FilterByKeystoneTags.DeepCopyInto(&out.FilterByKeystoneTags) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectFilter. +func (in *ProjectFilter) DeepCopy() *ProjectFilter { + if in == nil { + return nil } - if in.RngModel != nil { - in, out := &in.RngModel, &out.RngModel + out := new(ProjectFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProjectImport) DeepCopyInto(out *ProjectImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID *out = new(string) **out = **in } - if in.QemuGuestAgent != nil { - in, out := &in.QemuGuestAgent, &out.QemuGuestAgent - *out = new(bool) - **out = **in + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(ProjectFilter) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePropertiesHardware. -func (in *ImagePropertiesHardware) DeepCopy() *ImagePropertiesHardware { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectImport. +func (in *ProjectImport) DeepCopy() *ProjectImport { if in == nil { return nil } - out := new(ImagePropertiesHardware) + out := new(ProjectImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImagePropertiesOperatingSystem) DeepCopyInto(out *ImagePropertiesOperatingSystem) { +func (in *ProjectList) DeepCopyInto(out *ProjectList) { *out = *in - if in.Distro != nil { - in, out := &in.Distro, &out.Distro - *out = new(string) - **out = **in - } - if in.Version != nil { - in, out := &in.Version, &out.Version - *out = new(string) - **out = **in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Project, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePropertiesOperatingSystem. -func (in *ImagePropertiesOperatingSystem) DeepCopy() *ImagePropertiesOperatingSystem { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectList. +func (in *ProjectList) DeepCopy() *ProjectList { if in == nil { return nil } - out := new(ImagePropertiesOperatingSystem) + out := new(ProjectList) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ProjectList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageResourceSpec) DeepCopyInto(out *ImageResourceSpec) { +func (in *ProjectResourceSpec) DeepCopyInto(out *ProjectResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(OpenStackName) + *out = new(KeystoneName) **out = **in } - if in.Protected != nil { - in, out := &in.Protected, &out.Protected + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled *out = new(bool) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags - *out = make([]ImageTag, len(*in)) + *out = make([]KeystoneTag, len(*in)) copy(*out, *in) } - if in.Visibility != nil { - in, out := &in.Visibility, &out.Visibility - *out = new(ImageVisibility) - **out = **in - } - if in.Properties != nil { - in, out := &in.Properties, &out.Properties - *out = new(ImageProperties) - (*in).DeepCopyInto(*out) - } - if in.Content != nil { - in, out := &in.Content, &out.Content - *out = new(ImageContent) - (*in).DeepCopyInto(*out) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageResourceSpec. -func (in *ImageResourceSpec) DeepCopy() *ImageResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectResourceSpec. +func (in *ProjectResourceSpec) DeepCopy() *ProjectResourceSpec { if in == nil { return nil } - out := new(ImageResourceSpec) + out := new(ProjectResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageResourceStatus) DeepCopyInto(out *ImageResourceStatus) { +func (in *ProjectResourceStatus) DeepCopyInto(out *ProjectResourceStatus) { *out = *in - if in.Hash != nil { - in, out := &in.Hash, &out.Hash - *out = new(ImageHash) - **out = **in - } - if in.SizeB != nil { - in, out := &in.SizeB, &out.SizeB - *out = new(int64) - **out = **in - } - if in.VirtualSizeB != nil { - in, out := &in.VirtualSizeB, &out.VirtualSizeB - *out = new(int64) + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) **out = **in } if in.Tags != nil { @@ -1674,27 +3806,27 @@ func (in *ImageResourceStatus) DeepCopyInto(out *ImageResourceStatus) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageResourceStatus. -func (in *ImageResourceStatus) DeepCopy() *ImageResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectResourceStatus. +func (in *ProjectResourceStatus) DeepCopy() *ProjectResourceStatus { if in == nil { return nil } - out := new(ImageResourceStatus) + out := new(ProjectResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageSpec) DeepCopyInto(out *ImageSpec) { +func (in *ProjectSpec) DeepCopyInto(out *ProjectSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(ImageImport) + *out = new(ProjectImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ImageResourceSpec) + *out = new(ProjectResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -1702,21 +3834,26 @@ func (in *ImageSpec) DeepCopyInto(out *ImageSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageSpec. -func (in *ImageSpec) DeepCopy() *ImageSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectSpec. +func (in *ProjectSpec) DeepCopy() *ProjectSpec { if in == nil { return nil } - out := new(ImageSpec) + out := new(ProjectSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageStatus) DeepCopyInto(out *ImageStatus) { +func (in *ProjectStatus) DeepCopyInto(out *ProjectStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -1732,44 +3869,47 @@ func (in *ImageStatus) DeepCopyInto(out *ImageStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ImageResourceStatus) + *out = new(ProjectResourceStatus) (*in).DeepCopyInto(*out) } - in.ImageStatusExtra.DeepCopyInto(&out.ImageStatusExtra) + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatus. -func (in *ImageStatus) DeepCopy() *ImageStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectStatus. +func (in *ProjectStatus) DeepCopy() *ProjectStatus { if in == nil { return nil } - out := new(ImageStatus) + out := new(ProjectStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageStatusExtra) DeepCopyInto(out *ImageStatusExtra) { +func (in *ProviderPropertiesStatus) DeepCopyInto(out *ProviderPropertiesStatus) { *out = *in - if in.DownloadAttempts != nil { - in, out := &in.DownloadAttempts, &out.DownloadAttempts + if in.SegmentationID != nil { + in, out := &in.SegmentationID, &out.SegmentationID *out = new(int32) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatusExtra. -func (in *ImageStatusExtra) DeepCopy() *ImageStatusExtra { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderPropertiesStatus. +func (in *ProviderPropertiesStatus) DeepCopy() *ProviderPropertiesStatus { if in == nil { return nil } - out := new(ImageStatusExtra) + out := new(ProviderPropertiesStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPair) DeepCopyInto(out *KeyPair) { +func (in *Role) DeepCopyInto(out *Role) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -1777,18 +3917,18 @@ func (in *KeyPair) DeepCopyInto(out *KeyPair) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPair. -func (in *KeyPair) DeepCopy() *KeyPair { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Role. +func (in *Role) DeepCopy() *Role { if in == nil { return nil } - out := new(KeyPair) + out := new(Role) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *KeyPair) DeepCopyObject() runtime.Object { +func (in *Role) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1796,76 +3936,118 @@ func (in *KeyPair) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPairFilter) DeepCopyInto(out *KeyPairFilter) { +func (in *RoleAssignment) DeepCopyInto(out *RoleAssignment) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in - } + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairFilter. -func (in *KeyPairFilter) DeepCopy() *KeyPairFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignment. +func (in *RoleAssignment) DeepCopy() *RoleAssignment { if in == nil { return nil } - out := new(KeyPairFilter) + out := new(RoleAssignment) in.DeepCopyInto(out) return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RoleAssignment) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPairImport) DeepCopyInto(out *KeyPairImport) { +func (in *RoleAssignmentFilter) DeepCopyInto(out *RoleAssignmentFilter) { *out = *in - if in.ID != nil { - in, out := &in.ID, &out.ID - *out = new(string) + if in.RoleRef != nil { + in, out := &in.RoleRef, &out.RoleRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.UserRef != nil { + in, out := &in.UserRef, &out.UserRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.GroupRef != nil { + in, out := &in.GroupRef, &out.GroupRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) **out = **in } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignmentFilter. +func (in *RoleAssignmentFilter) DeepCopy() *RoleAssignmentFilter { + if in == nil { + return nil + } + out := new(RoleAssignmentFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RoleAssignmentImport) DeepCopyInto(out *RoleAssignmentImport) { + *out = *in if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(KeyPairFilter) + *out = new(RoleAssignmentFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairImport. -func (in *KeyPairImport) DeepCopy() *KeyPairImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignmentImport. +func (in *RoleAssignmentImport) DeepCopy() *RoleAssignmentImport { if in == nil { return nil } - out := new(KeyPairImport) + out := new(RoleAssignmentImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPairList) DeepCopyInto(out *KeyPairList) { +func (in *RoleAssignmentList) DeepCopyInto(out *RoleAssignmentList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]KeyPair, len(*in)) + *out = make([]RoleAssignment, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairList. -func (in *KeyPairList) DeepCopy() *KeyPairList { + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignmentList. +func (in *RoleAssignmentList) DeepCopy() *RoleAssignmentList { if in == nil { return nil } - out := new(KeyPairList) + out := new(RoleAssignmentList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *KeyPairList) DeepCopyObject() runtime.Object { +func (in *RoleAssignmentList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1873,56 +4055,66 @@ func (in *KeyPairList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPairResourceSpec) DeepCopyInto(out *KeyPairResourceSpec) { +func (in *RoleAssignmentResourceSpec) DeepCopyInto(out *RoleAssignmentResourceSpec) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) + if in.UserRef != nil { + in, out := &in.UserRef, &out.UserRef + *out = new(KubernetesNameRef) **out = **in } - if in.Type != nil { - in, out := &in.Type, &out.Type - *out = new(string) + if in.GroupRef != nil { + in, out := &in.GroupRef, &out.GroupRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairResourceSpec. -func (in *KeyPairResourceSpec) DeepCopy() *KeyPairResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignmentResourceSpec. +func (in *RoleAssignmentResourceSpec) DeepCopy() *RoleAssignmentResourceSpec { if in == nil { return nil } - out := new(KeyPairResourceSpec) + out := new(RoleAssignmentResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPairResourceStatus) DeepCopyInto(out *KeyPairResourceStatus) { +func (in *RoleAssignmentResourceStatus) DeepCopyInto(out *RoleAssignmentResourceStatus) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairResourceStatus. -func (in *KeyPairResourceStatus) DeepCopy() *KeyPairResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignmentResourceStatus. +func (in *RoleAssignmentResourceStatus) DeepCopy() *RoleAssignmentResourceStatus { if in == nil { return nil } - out := new(KeyPairResourceStatus) + out := new(RoleAssignmentResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPairSpec) DeepCopyInto(out *KeyPairSpec) { +func (in *RoleAssignmentSpec) DeepCopyInto(out *RoleAssignmentSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(KeyPairImport) + *out = new(RoleAssignmentImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(KeyPairResourceSpec) + *out = new(RoleAssignmentResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -1930,21 +4122,26 @@ func (in *KeyPairSpec) DeepCopyInto(out *KeyPairSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairSpec. -func (in *KeyPairSpec) DeepCopy() *KeyPairSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignmentSpec. +func (in *RoleAssignmentSpec) DeepCopy() *RoleAssignmentSpec { if in == nil { return nil } - out := new(KeyPairSpec) + out := new(RoleAssignmentSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *KeyPairStatus) DeepCopyInto(out *KeyPairStatus) { +func (in *RoleAssignmentStatus) DeepCopyInto(out *RoleAssignmentStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -1953,108 +4150,54 @@ func (in *KeyPairStatus) DeepCopyInto(out *KeyPairStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.ID != nil { - in, out := &in.ID, &out.ID - *out = new(string) - **out = **in - } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(KeyPairResourceStatus) + *out = new(RoleAssignmentResourceStatus) **out = **in } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyPairStatus. -func (in *KeyPairStatus) DeepCopy() *KeyPairStatus { - if in == nil { - return nil - } - out := new(KeyPairStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ManagedOptions) DeepCopyInto(out *ManagedOptions) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedOptions. -func (in *ManagedOptions) DeepCopy() *ManagedOptions { - if in == nil { - return nil + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() } - out := new(ManagedOptions) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Network) DeepCopyInto(out *Network) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network. -func (in *Network) DeepCopy() *Network { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleAssignmentStatus. +func (in *RoleAssignmentStatus) DeepCopy() *RoleAssignmentStatus { if in == nil { return nil } - out := new(Network) + out := new(RoleAssignmentStatus) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Network) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkFilter) DeepCopyInto(out *NetworkFilter) { +func (in *RoleFilter) DeepCopyInto(out *RoleFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in - } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(NeutronDescription) - **out = **in - } - if in.External != nil { - in, out := &in.External, &out.External - *out = new(bool) + *out = new(KeystoneName) **out = **in } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef *out = new(KubernetesNameRef) **out = **in } - in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkFilter. -func (in *NetworkFilter) DeepCopy() *NetworkFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleFilter. +func (in *RoleFilter) DeepCopy() *RoleFilter { if in == nil { return nil } - out := new(NetworkFilter) + out := new(RoleFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkImport) DeepCopyInto(out *NetworkImport) { +func (in *RoleImport) DeepCopyInto(out *RoleImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -2063,47 +4206,47 @@ func (in *NetworkImport) DeepCopyInto(out *NetworkImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(NetworkFilter) + *out = new(RoleFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkImport. -func (in *NetworkImport) DeepCopy() *NetworkImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleImport. +func (in *RoleImport) DeepCopy() *RoleImport { if in == nil { return nil } - out := new(NetworkImport) + out := new(RoleImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkList) DeepCopyInto(out *NetworkList) { +func (in *RoleList) DeepCopyInto(out *RoleList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Network, len(*in)) + *out = make([]Role, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkList. -func (in *NetworkList) DeepCopy() *NetworkList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleList. +func (in *RoleList) DeepCopy() *RoleList { if in == nil { return nil } - out := new(NetworkList) + out := new(RoleList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NetworkList) DeepCopyObject() runtime.Object { +func (in *RoleList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2111,147 +4254,61 @@ func (in *NetworkList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkResourceSpec) DeepCopyInto(out *NetworkResourceSpec) { +func (in *RoleResourceSpec) DeepCopyInto(out *RoleResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(OpenStackName) + *out = new(KeystoneName) **out = **in } if in.Description != nil { in, out := &in.Description, &out.Description - *out = new(NeutronDescription) - **out = **in - } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } - if in.AdminStateUp != nil { - in, out := &in.AdminStateUp, &out.AdminStateUp - *out = new(bool) - **out = **in - } - if in.DNSDomain != nil { - in, out := &in.DNSDomain, &out.DNSDomain - *out = new(DNSDomain) - **out = **in - } - if in.MTU != nil { - in, out := &in.MTU, &out.MTU - *out = new(MTU) - **out = **in - } - if in.PortSecurityEnabled != nil { - in, out := &in.PortSecurityEnabled, &out.PortSecurityEnabled - *out = new(bool) - **out = **in - } - if in.External != nil { - in, out := &in.External, &out.External - *out = new(bool) - **out = **in - } - if in.Shared != nil { - in, out := &in.Shared, &out.Shared - *out = new(bool) + *out = new(string) **out = **in } - if in.AvailabilityZoneHints != nil { - in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints - *out = make([]AvailabilityZoneHint, len(*in)) - copy(*out, *in) - } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef *out = new(KubernetesNameRef) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkResourceSpec. -func (in *NetworkResourceSpec) DeepCopy() *NetworkResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleResourceSpec. +func (in *RoleResourceSpec) DeepCopy() *RoleResourceSpec { if in == nil { return nil } - out := new(NetworkResourceSpec) + out := new(RoleResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkResourceStatus) DeepCopyInto(out *NetworkResourceStatus) { +func (in *RoleResourceStatus) DeepCopyInto(out *RoleResourceStatus) { *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) - } - in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) - if in.AdminStateUp != nil { - in, out := &in.AdminStateUp, &out.AdminStateUp - *out = new(bool) - **out = **in - } - if in.AvailabilityZoneHints != nil { - in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.MTU != nil { - in, out := &in.MTU, &out.MTU - *out = new(int32) - **out = **in - } - if in.PortSecurityEnabled != nil { - in, out := &in.PortSecurityEnabled, &out.PortSecurityEnabled - *out = new(bool) - **out = **in - } - if in.Provider != nil { - in, out := &in.Provider, &out.Provider - *out = new(ProviderPropertiesStatus) - (*in).DeepCopyInto(*out) - } - if in.External != nil { - in, out := &in.External, &out.External - *out = new(bool) - **out = **in - } - if in.Shared != nil { - in, out := &in.Shared, &out.Shared - *out = new(bool) - **out = **in - } - if in.Subnets != nil { - in, out := &in.Subnets, &out.Subnets - *out = make([]string, len(*in)) - copy(*out, *in) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkResourceStatus. -func (in *NetworkResourceStatus) DeepCopy() *NetworkResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleResourceStatus. +func (in *RoleResourceStatus) DeepCopy() *RoleResourceStatus { if in == nil { return nil } - out := new(NetworkResourceStatus) + out := new(RoleResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { +func (in *RoleSpec) DeepCopyInto(out *RoleSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(NetworkImport) + *out = new(RoleImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(NetworkResourceSpec) + *out = new(RoleResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -2259,21 +4316,26 @@ func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkSpec. -func (in *NetworkSpec) DeepCopy() *NetworkSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleSpec. +func (in *RoleSpec) DeepCopy() *RoleSpec { if in == nil { return nil } - out := new(NetworkSpec) + out := new(RoleSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) { +func (in *RoleStatus) DeepCopyInto(out *RoleStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -2289,51 +4351,27 @@ func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(NetworkResourceStatus) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkStatus. -func (in *NetworkStatus) DeepCopy() *NetworkStatus { - if in == nil { - return nil - } - out := new(NetworkStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NeutronStatusMetadata) DeepCopyInto(out *NeutronStatusMetadata) { - *out = *in - if in.CreatedAt != nil { - in, out := &in.CreatedAt, &out.CreatedAt - *out = (*in).DeepCopy() + *out = new(RoleResourceStatus) + **out = **in } - if in.UpdatedAt != nil { - in, out := &in.UpdatedAt, &out.UpdatedAt + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime *out = (*in).DeepCopy() } - if in.RevisionNumber != nil { - in, out := &in.RevisionNumber, &out.RevisionNumber - *out = new(int64) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronStatusMetadata. -func (in *NeutronStatusMetadata) DeepCopy() *NeutronStatusMetadata { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleStatus. +func (in *RoleStatus) DeepCopy() *RoleStatus { if in == nil { return nil } - out := new(NeutronStatusMetadata) + out := new(RoleStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Port) DeepCopyInto(out *Port) { +func (in *Router) DeepCopyInto(out *Router) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -2341,18 +4379,18 @@ func (in *Port) DeepCopyInto(out *Port) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Port. -func (in *Port) DeepCopy() *Port { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Router. +func (in *Router) DeepCopy() *Router { if in == nil { return nil } - out := new(Port) + out := new(Router) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Port) DeepCopyObject() runtime.Object { +func (in *Router) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2360,7 +4398,7 @@ func (in *Port) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortFilter) DeepCopyInto(out *PortFilter) { +func (in *RouterFilter) DeepCopyInto(out *RouterFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name @@ -2377,26 +4415,21 @@ func (in *PortFilter) DeepCopyInto(out *PortFilter) { *out = new(KubernetesNameRef) **out = **in } - if in.AdminStateUp != nil { - in, out := &in.AdminStateUp, &out.AdminStateUp - *out = new(bool) - **out = **in - } in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortFilter. -func (in *PortFilter) DeepCopy() *PortFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterFilter. +func (in *RouterFilter) DeepCopy() *RouterFilter { if in == nil { return nil } - out := new(PortFilter) + out := new(RouterFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortImport) DeepCopyInto(out *PortImport) { +func (in *RouterImport) DeepCopyInto(out *RouterImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -2405,47 +4438,74 @@ func (in *PortImport) DeepCopyInto(out *PortImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(PortFilter) + *out = new(RouterFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortImport. -func (in *PortImport) DeepCopy() *PortImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterImport. +func (in *RouterImport) DeepCopy() *RouterImport { if in == nil { return nil } - out := new(PortImport) + out := new(RouterImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortList) DeepCopyInto(out *PortList) { +func (in *RouterInterface) DeepCopyInto(out *RouterInterface) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterface. +func (in *RouterInterface) DeepCopy() *RouterInterface { + if in == nil { + return nil + } + out := new(RouterInterface) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RouterInterface) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouterInterfaceList) DeepCopyInto(out *RouterInterfaceList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Port, len(*in)) + *out = make([]RouterInterface, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortList. -func (in *PortList) DeepCopy() *PortList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterfaceList. +func (in *RouterInterfaceList) DeepCopy() *RouterInterfaceList { if in == nil { return nil } - out := new(PortList) + out := new(RouterInterfaceList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PortList) DeepCopyObject() runtime.Object { +func (in *RouterInterfaceList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2453,37 +4513,95 @@ func (in *PortList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortRangeSpec) DeepCopyInto(out *PortRangeSpec) { +func (in *RouterInterfaceSpec) DeepCopyInto(out *RouterInterfaceSpec) { *out = *in + if in.SubnetRef != nil { + in, out := &in.SubnetRef, &out.SubnetRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortRangeSpec. -func (in *PortRangeSpec) DeepCopy() *PortRangeSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterfaceSpec. +func (in *RouterInterfaceSpec) DeepCopy() *RouterInterfaceSpec { if in == nil { return nil } - out := new(PortRangeSpec) + out := new(RouterInterfaceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortRangeStatus) DeepCopyInto(out *PortRangeStatus) { +func (in *RouterInterfaceStatus) DeepCopyInto(out *RouterInterfaceStatus) { *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortRangeStatus. -func (in *PortRangeStatus) DeepCopy() *PortRangeStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterfaceStatus. +func (in *RouterInterfaceStatus) DeepCopy() *RouterInterfaceStatus { if in == nil { return nil } - out := new(PortRangeStatus) + out := new(RouterInterfaceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortResourceSpec) DeepCopyInto(out *PortResourceSpec) { +func (in *RouterList) DeepCopyInto(out *RouterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Router, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterList. +func (in *RouterList) DeepCopy() *RouterList { + if in == nil { + return nil + } + out := new(RouterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RouterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouterResourceSpec) DeepCopyInto(out *RouterResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name @@ -2500,28 +4618,24 @@ func (in *PortResourceSpec) DeepCopyInto(out *PortResourceSpec) { *out = make([]NeutronTag, len(*in)) copy(*out, *in) } - if in.AllowedAddressPairs != nil { - in, out := &in.AllowedAddressPairs, &out.AllowedAddressPairs - *out = make([]AllowedAddressPair, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Addresses != nil { - in, out := &in.Addresses, &out.Addresses - *out = make([]Address, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } if in.AdminStateUp != nil { in, out := &in.AdminStateUp, &out.AdminStateUp *out = new(bool) **out = **in } - if in.SecurityGroupRefs != nil { - in, out := &in.SecurityGroupRefs, &out.SecurityGroupRefs - *out = make([]OpenStackName, len(*in)) + if in.ExternalGateways != nil { + in, out := &in.ExternalGateways, &out.ExternalGateways + *out = make([]ExternalGateway, len(*in)) + copy(*out, *in) + } + if in.Distributed != nil { + in, out := &in.Distributed, &out.Distributed + *out = new(bool) + **out = **in + } + if in.AvailabilityZoneHints != nil { + in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints + *out = make([]AvailabilityZoneHint, len(*in)) copy(*out, *in) } if in.ProjectRef != nil { @@ -2531,18 +4645,18 @@ func (in *PortResourceSpec) DeepCopyInto(out *PortResourceSpec) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortResourceSpec. -func (in *PortResourceSpec) DeepCopy() *PortResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterResourceSpec. +func (in *RouterResourceSpec) DeepCopy() *RouterResourceSpec { if in == nil { return nil } - out := new(PortResourceSpec) + out := new(RouterResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortResourceStatus) DeepCopyInto(out *PortResourceStatus) { +func (in *RouterResourceStatus) DeepCopyInto(out *RouterResourceStatus) { *out = *in if in.Tags != nil { in, out := &in.Tags, &out.Tags @@ -2554,55 +4668,39 @@ func (in *PortResourceStatus) DeepCopyInto(out *PortResourceStatus) { *out = new(bool) **out = **in } - if in.AllowedAddressPairs != nil { - in, out := &in.AllowedAddressPairs, &out.AllowedAddressPairs - *out = make([]AllowedAddressPairStatus, len(*in)) - copy(*out, *in) - } - if in.FixedIPs != nil { - in, out := &in.FixedIPs, &out.FixedIPs - *out = make([]FixedIPStatus, len(*in)) + if in.ExternalGateways != nil { + in, out := &in.ExternalGateways, &out.ExternalGateways + *out = make([]ExternalGatewayStatus, len(*in)) copy(*out, *in) } - if in.SecurityGroups != nil { - in, out := &in.SecurityGroups, &out.SecurityGroups + if in.AvailabilityZoneHints != nil { + in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints *out = make([]string, len(*in)) copy(*out, *in) } - if in.PropagateUplinkStatus != nil { - in, out := &in.PropagateUplinkStatus, &out.PropagateUplinkStatus - *out = new(bool) - **out = **in - } - if in.PortSecurityEnabled != nil { - in, out := &in.PortSecurityEnabled, &out.PortSecurityEnabled - *out = new(bool) - **out = **in - } - in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortResourceStatus. -func (in *PortResourceStatus) DeepCopy() *PortResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterResourceStatus. +func (in *RouterResourceStatus) DeepCopy() *RouterResourceStatus { if in == nil { return nil } - out := new(PortResourceStatus) + out := new(RouterResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortSpec) DeepCopyInto(out *PortSpec) { +func (in *RouterSpec) DeepCopyInto(out *RouterSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(PortImport) + *out = new(RouterImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(PortResourceSpec) + *out = new(RouterResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -2610,21 +4708,26 @@ func (in *PortSpec) DeepCopyInto(out *PortSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortSpec. -func (in *PortSpec) DeepCopy() *PortSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterSpec. +func (in *RouterSpec) DeepCopy() *RouterSpec { if in == nil { return nil } - out := new(PortSpec) + out := new(RouterSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PortStatus) DeepCopyInto(out *PortStatus) { +func (in *RouterStatus) DeepCopyInto(out *RouterStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -2640,23 +4743,27 @@ func (in *PortStatus) DeepCopyInto(out *PortStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(PortResourceStatus) + *out = new(RouterResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortStatus. -func (in *PortStatus) DeepCopy() *PortStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterStatus. +func (in *RouterStatus) DeepCopy() *RouterStatus { if in == nil { return nil } - out := new(PortStatus) + out := new(RouterStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Project) DeepCopyInto(out *Project) { +func (in *SecurityGroup) DeepCopyInto(out *SecurityGroup) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -2664,18 +4771,18 @@ func (in *Project) DeepCopyInto(out *Project) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Project. -func (in *Project) DeepCopy() *Project { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroup. +func (in *SecurityGroup) DeepCopy() *SecurityGroup { if in == nil { return nil } - out := new(Project) + out := new(SecurityGroup) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Project) DeepCopyObject() runtime.Object { +func (in *SecurityGroup) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2683,28 +4790,38 @@ func (in *Project) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectFilter) DeepCopyInto(out *ProjectFilter) { +func (in *SecurityGroupFilter) DeepCopyInto(out *SecurityGroupFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(KeystoneName) + *out = new(OpenStackName) **out = **in } - in.FilterByKeystoneTags.DeepCopyInto(&out.FilterByKeystoneTags) + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectFilter. -func (in *ProjectFilter) DeepCopy() *ProjectFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupFilter. +func (in *SecurityGroupFilter) DeepCopy() *SecurityGroupFilter { if in == nil { return nil } - out := new(ProjectFilter) + out := new(SecurityGroupFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectImport) DeepCopyInto(out *ProjectImport) { +func (in *SecurityGroupImport) DeepCopyInto(out *SecurityGroupImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -2713,47 +4830,47 @@ func (in *ProjectImport) DeepCopyInto(out *ProjectImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(ProjectFilter) + *out = new(SecurityGroupFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectImport. -func (in *ProjectImport) DeepCopy() *ProjectImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupImport. +func (in *SecurityGroupImport) DeepCopy() *SecurityGroupImport { if in == nil { return nil } - out := new(ProjectImport) + out := new(SecurityGroupImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectList) DeepCopyInto(out *ProjectList) { +func (in *SecurityGroupList) DeepCopyInto(out *SecurityGroupList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Project, len(*in)) + *out = make([]SecurityGroup, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectList. -func (in *ProjectList) DeepCopy() *ProjectList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupList. +func (in *SecurityGroupList) DeepCopy() *SecurityGroupList { if in == nil { return nil } - out := new(ProjectList) + out := new(SecurityGroupList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ProjectList) DeepCopyObject() runtime.Object { +func (in *SecurityGroupList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2761,76 +4878,151 @@ func (in *ProjectList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectResourceSpec) DeepCopyInto(out *ProjectResourceSpec) { +func (in *SecurityGroupResourceSpec) DeepCopyInto(out *SecurityGroupResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(KeystoneName) + *out = new(OpenStackName) **out = **in } if in.Description != nil { in, out := &in.Description, &out.Description - *out = new(string) + *out = new(NeutronDescription) **out = **in } - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) + } + if in.Stateful != nil { + in, out := &in.Stateful, &out.Stateful *out = new(bool) **out = **in } + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]SecurityGroupRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupResourceSpec. +func (in *SecurityGroupResourceSpec) DeepCopy() *SecurityGroupResourceSpec { + if in == nil { + return nil + } + out := new(SecurityGroupResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityGroupResourceStatus) DeepCopyInto(out *SecurityGroupResourceStatus) { + *out = *in if in.Tags != nil { in, out := &in.Tags, &out.Tags - *out = make([]KeystoneTag, len(*in)) + *out = make([]string, len(*in)) copy(*out, *in) } + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]SecurityGroupRuleStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectResourceSpec. -func (in *ProjectResourceSpec) DeepCopy() *ProjectResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupResourceStatus. +func (in *SecurityGroupResourceStatus) DeepCopy() *SecurityGroupResourceStatus { if in == nil { return nil } - out := new(ProjectResourceSpec) + out := new(SecurityGroupResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectResourceStatus) DeepCopyInto(out *ProjectResourceStatus) { +func (in *SecurityGroupRule) DeepCopyInto(out *SecurityGroupRule) { *out = *in - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled - *out = new(bool) + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) **out = **in } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) + if in.Direction != nil { + in, out := &in.Direction, &out.Direction + *out = new(RuleDirection) + **out = **in + } + if in.RemoteIPPrefix != nil { + in, out := &in.RemoteIPPrefix, &out.RemoteIPPrefix + *out = new(CIDR) + **out = **in + } + if in.Protocol != nil { + in, out := &in.Protocol, &out.Protocol + *out = new(Protocol) + **out = **in + } + if in.PortRange != nil { + in, out := &in.PortRange, &out.PortRange + *out = new(PortRangeSpec) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectResourceStatus. -func (in *ProjectResourceStatus) DeepCopy() *ProjectResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupRule. +func (in *SecurityGroupRule) DeepCopy() *SecurityGroupRule { if in == nil { return nil } - out := new(ProjectResourceStatus) + out := new(SecurityGroupRule) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectSpec) DeepCopyInto(out *ProjectSpec) { +func (in *SecurityGroupRuleStatus) DeepCopyInto(out *SecurityGroupRuleStatus) { + *out = *in + if in.PortRange != nil { + in, out := &in.PortRange, &out.PortRange + *out = new(PortRangeStatus) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupRuleStatus. +func (in *SecurityGroupRuleStatus) DeepCopy() *SecurityGroupRuleStatus { + if in == nil { + return nil + } + out := new(SecurityGroupRuleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityGroupSpec) DeepCopyInto(out *SecurityGroupSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(ProjectImport) + *out = new(SecurityGroupImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ProjectResourceSpec) + *out = new(SecurityGroupResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -2838,21 +5030,26 @@ func (in *ProjectSpec) DeepCopyInto(out *ProjectSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectSpec. -func (in *ProjectSpec) DeepCopy() *ProjectSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupSpec. +func (in *SecurityGroupSpec) DeepCopy() *SecurityGroupSpec { if in == nil { return nil } - out := new(ProjectSpec) + out := new(SecurityGroupSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProjectStatus) DeepCopyInto(out *ProjectStatus) { +func (in *SecurityGroupStatus) DeepCopyInto(out *SecurityGroupStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -2868,43 +5065,95 @@ func (in *ProjectStatus) DeepCopyInto(out *ProjectStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ProjectResourceStatus) + *out = new(SecurityGroupResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupStatus. +func (in *SecurityGroupStatus) DeepCopy() *SecurityGroupStatus { + if in == nil { + return nil + } + out := new(SecurityGroupStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Server) DeepCopyInto(out *Server) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Server. +func (in *Server) DeepCopy() *Server { + if in == nil { + return nil + } + out := new(Server) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Server) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerBootVolumeSpec) DeepCopyInto(out *ServerBootVolumeSpec) { + *out = *in + if in.Tag != nil { + in, out := &in.Tag, &out.Tag + *out = new(string) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectStatus. -func (in *ProjectStatus) DeepCopy() *ProjectStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerBootVolumeSpec. +func (in *ServerBootVolumeSpec) DeepCopy() *ServerBootVolumeSpec { if in == nil { return nil } - out := new(ProjectStatus) + out := new(ServerBootVolumeSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ProviderPropertiesStatus) DeepCopyInto(out *ProviderPropertiesStatus) { +func (in *ServerFilter) DeepCopyInto(out *ServerFilter) { *out = *in - if in.SegmentationID != nil { - in, out := &in.SegmentationID, &out.SegmentationID - *out = new(int32) + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) **out = **in } + in.FilterByServerTags.DeepCopyInto(&out.FilterByServerTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderPropertiesStatus. -func (in *ProviderPropertiesStatus) DeepCopy() *ProviderPropertiesStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerFilter. +func (in *ServerFilter) DeepCopy() *ServerFilter { if in == nil { return nil } - out := new(ProviderPropertiesStatus) + out := new(ServerFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Role) DeepCopyInto(out *Role) { +func (in *ServerGroup) DeepCopyInto(out *ServerGroup) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -2912,18 +5161,18 @@ func (in *Role) DeepCopyInto(out *Role) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Role. -func (in *Role) DeepCopy() *Role { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroup. +func (in *ServerGroup) DeepCopy() *ServerGroup { if in == nil { return nil } - out := new(Role) + out := new(ServerGroup) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Role) DeepCopyObject() runtime.Object { +func (in *ServerGroup) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -2931,32 +5180,27 @@ func (in *Role) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoleFilter) DeepCopyInto(out *RoleFilter) { +func (in *ServerGroupFilter) DeepCopyInto(out *ServerGroupFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(KeystoneName) - **out = **in - } - if in.DomainRef != nil { - in, out := &in.DomainRef, &out.DomainRef - *out = new(KubernetesNameRef) + *out = new(OpenStackName) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleFilter. -func (in *RoleFilter) DeepCopy() *RoleFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupFilter. +func (in *ServerGroupFilter) DeepCopy() *ServerGroupFilter { if in == nil { return nil } - out := new(RoleFilter) + out := new(ServerGroupFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoleImport) DeepCopyInto(out *RoleImport) { +func (in *ServerGroupImport) DeepCopyInto(out *ServerGroupImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -2965,47 +5209,47 @@ func (in *RoleImport) DeepCopyInto(out *RoleImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(RoleFilter) + *out = new(ServerGroupFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleImport. -func (in *RoleImport) DeepCopy() *RoleImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupImport. +func (in *ServerGroupImport) DeepCopy() *ServerGroupImport { if in == nil { return nil } - out := new(RoleImport) + out := new(ServerGroupImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoleList) DeepCopyInto(out *RoleList) { +func (in *ServerGroupList) DeepCopyInto(out *ServerGroupList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Role, len(*in)) + *out = make([]ServerGroup, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleList. -func (in *RoleList) DeepCopy() *RoleList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupList. +func (in *ServerGroupList) DeepCopy() *ServerGroupList { if in == nil { return nil } - out := new(RoleList) + out := new(ServerGroupList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RoleList) DeepCopyObject() runtime.Object { +func (in *ServerGroupList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -3013,61 +5257,96 @@ func (in *RoleList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoleResourceSpec) DeepCopyInto(out *RoleResourceSpec) { +func (in *ServerGroupResourceSpec) DeepCopyInto(out *ServerGroupResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name - *out = new(KeystoneName) + *out = new(OpenStackName) **out = **in } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(string) + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = new(ServerGroupRules) **out = **in } - if in.DomainRef != nil { - in, out := &in.DomainRef, &out.DomainRef - *out = new(KubernetesNameRef) - **out = **in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupResourceSpec. +func (in *ServerGroupResourceSpec) DeepCopy() *ServerGroupResourceSpec { + if in == nil { + return nil } + out := new(ServerGroupResourceSpec) + in.DeepCopyInto(out) + return out } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleResourceSpec. -func (in *RoleResourceSpec) DeepCopy() *RoleResourceSpec { +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerGroupResourceStatus) DeepCopyInto(out *ServerGroupResourceStatus) { + *out = *in + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = new(ServerGroupRulesStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupResourceStatus. +func (in *ServerGroupResourceStatus) DeepCopy() *ServerGroupResourceStatus { if in == nil { return nil } - out := new(RoleResourceSpec) + out := new(ServerGroupResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoleResourceStatus) DeepCopyInto(out *RoleResourceStatus) { +func (in *ServerGroupRules) DeepCopyInto(out *ServerGroupRules) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleResourceStatus. -func (in *RoleResourceStatus) DeepCopy() *RoleResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupRules. +func (in *ServerGroupRules) DeepCopy() *ServerGroupRules { if in == nil { return nil } - out := new(RoleResourceStatus) + out := new(ServerGroupRules) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoleSpec) DeepCopyInto(out *RoleSpec) { +func (in *ServerGroupRulesStatus) DeepCopyInto(out *ServerGroupRulesStatus) { + *out = *in + if in.MaxServerPerHost != nil { + in, out := &in.MaxServerPerHost, &out.MaxServerPerHost + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupRulesStatus. +func (in *ServerGroupRulesStatus) DeepCopy() *ServerGroupRulesStatus { + if in == nil { + return nil + } + out := new(ServerGroupRulesStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerGroupSpec) DeepCopyInto(out *ServerGroupSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(RoleImport) + *out = new(ServerGroupImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(RoleResourceSpec) + *out = new(ServerGroupResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -3075,21 +5354,26 @@ func (in *RoleSpec) DeepCopyInto(out *RoleSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleSpec. -func (in *RoleSpec) DeepCopy() *RoleSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupSpec. +func (in *ServerGroupSpec) DeepCopy() *ServerGroupSpec { if in == nil { return nil } - out := new(RoleSpec) + out := new(ServerGroupSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RoleStatus) DeepCopyInto(out *RoleStatus) { +func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -3105,81 +5389,27 @@ func (in *RoleStatus) DeepCopyInto(out *RoleStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(RoleResourceStatus) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleStatus. -func (in *RoleStatus) DeepCopy() *RoleStatus { - if in == nil { - return nil - } - out := new(RoleStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Router) DeepCopyInto(out *Router) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Router. -func (in *Router) DeepCopy() *Router { - if in == nil { - return nil - } - out := new(Router) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Router) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterFilter) DeepCopyInto(out *RouterFilter) { - *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in - } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(NeutronDescription) - **out = **in + *out = new(ServerGroupResourceStatus) + (*in).DeepCopyInto(*out) } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef - *out = new(KubernetesNameRef) - **out = **in + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() } - in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterFilter. -func (in *RouterFilter) DeepCopy() *RouterFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupStatus. +func (in *ServerGroupStatus) DeepCopy() *ServerGroupStatus { if in == nil { return nil } - out := new(RouterFilter) + out := new(ServerGroupStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterImport) DeepCopyInto(out *RouterImport) { +func (in *ServerImport) DeepCopyInto(out *ServerImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -3188,74 +5418,82 @@ func (in *RouterImport) DeepCopyInto(out *RouterImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(RouterFilter) + *out = new(ServerFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterImport. -func (in *RouterImport) DeepCopy() *RouterImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerImport. +func (in *ServerImport) DeepCopy() *ServerImport { if in == nil { return nil } - out := new(RouterImport) + out := new(ServerImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterInterface) DeepCopyInto(out *RouterInterface) { +func (in *ServerInterfaceFixedIP) DeepCopyInto(out *ServerInterfaceFixedIP) { *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterface. -func (in *RouterInterface) DeepCopy() *RouterInterface { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerInterfaceFixedIP. +func (in *ServerInterfaceFixedIP) DeepCopy() *ServerInterfaceFixedIP { if in == nil { return nil } - out := new(RouterInterface) + out := new(ServerInterfaceFixedIP) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RouterInterface) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerInterfaceStatus) DeepCopyInto(out *ServerInterfaceStatus) { + *out = *in + if in.FixedIPs != nil { + in, out := &in.FixedIPs, &out.FixedIPs + *out = make([]ServerInterfaceFixedIP, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerInterfaceStatus. +func (in *ServerInterfaceStatus) DeepCopy() *ServerInterfaceStatus { + if in == nil { + return nil } - return nil + out := new(ServerInterfaceStatus) + in.DeepCopyInto(out) + return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterInterfaceList) DeepCopyInto(out *RouterInterfaceList) { +func (in *ServerList) DeepCopyInto(out *ServerList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]RouterInterface, len(*in)) + *out = make([]Server, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterfaceList. -func (in *RouterInterfaceList) DeepCopy() *RouterInterfaceList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerList. +func (in *ServerList) DeepCopy() *ServerList { if in == nil { return nil } - out := new(RouterInterfaceList) + out := new(ServerList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RouterInterfaceList) DeepCopyObject() runtime.Object { +func (in *ServerList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -3263,185 +5501,229 @@ func (in *RouterInterfaceList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterInterfaceSpec) DeepCopyInto(out *RouterInterfaceSpec) { +func (in *ServerMetadata) DeepCopyInto(out *ServerMetadata) { *out = *in - if in.SubnetRef != nil { - in, out := &in.SubnetRef, &out.SubnetRef - *out = new(KubernetesNameRef) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterfaceSpec. -func (in *RouterInterfaceSpec) DeepCopy() *RouterInterfaceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerMetadata. +func (in *ServerMetadata) DeepCopy() *ServerMetadata { if in == nil { return nil } - out := new(RouterInterfaceSpec) + out := new(ServerMetadata) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterInterfaceStatus) DeepCopyInto(out *RouterInterfaceStatus) { +func (in *ServerMetadataStatus) DeepCopyInto(out *ServerMetadataStatus) { *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ID != nil { - in, out := &in.ID, &out.ID - *out = new(string) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterInterfaceStatus. -func (in *RouterInterfaceStatus) DeepCopy() *RouterInterfaceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerMetadataStatus. +func (in *ServerMetadataStatus) DeepCopy() *ServerMetadataStatus { if in == nil { return nil } - out := new(RouterInterfaceStatus) + out := new(ServerMetadataStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterList) DeepCopyInto(out *RouterList) { +func (in *ServerPortSpec) DeepCopyInto(out *ServerPortSpec) { *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Router, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.PortRef != nil { + in, out := &in.PortRef, &out.PortRef + *out = new(KubernetesNameRef) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterList. -func (in *RouterList) DeepCopy() *RouterList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerPortSpec. +func (in *ServerPortSpec) DeepCopy() *ServerPortSpec { if in == nil { return nil } - out := new(RouterList) + out := new(ServerPortSpec) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *RouterList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterResourceSpec) DeepCopyInto(out *RouterResourceSpec) { +func (in *ServerResourceSpec) DeepCopyInto(out *ServerResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(OpenStackName) **out = **in } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(NeutronDescription) + if in.ImageRef != nil { + in, out := &in.ImageRef, &out.ImageRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.BootVolume != nil { + in, out := &in.BootVolume, &out.BootVolume + *out = new(ServerBootVolumeSpec) + (*in).DeepCopyInto(*out) + } + if in.UserData != nil { + in, out := &in.UserData, &out.UserData + *out = new(UserDataSpec) + (*in).DeepCopyInto(*out) + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]ServerPortSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]ServerVolumeSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.KeypairRef != nil { + in, out := &in.KeypairRef, &out.KeypairRef + *out = new(KubernetesNameRef) **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags - *out = make([]NeutronTag, len(*in)) + *out = make([]ServerTag, len(*in)) copy(*out, *in) } - if in.AdminStateUp != nil { - in, out := &in.AdminStateUp, &out.AdminStateUp - *out = new(bool) - **out = **in - } - if in.ExternalGateways != nil { - in, out := &in.ExternalGateways, &out.ExternalGateways - *out = make([]ExternalGateway, len(*in)) + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make([]ServerMetadata, len(*in)) copy(*out, *in) } - if in.Distributed != nil { - in, out := &in.Distributed, &out.Distributed + if in.ConfigDrive != nil { + in, out := &in.ConfigDrive, &out.ConfigDrive *out = new(bool) **out = **in } - if in.AvailabilityZoneHints != nil { - in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints - *out = make([]AvailabilityZoneHint, len(*in)) - copy(*out, *in) - } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef - *out = new(KubernetesNameRef) - **out = **in + if in.SchedulerHints != nil { + in, out := &in.SchedulerHints, &out.SchedulerHints + *out = new(ServerSchedulerHints) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterResourceSpec. -func (in *RouterResourceSpec) DeepCopy() *RouterResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerResourceSpec. +func (in *ServerResourceSpec) DeepCopy() *ServerResourceSpec { if in == nil { return nil } - out := new(RouterResourceSpec) + out := new(ServerResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterResourceStatus) DeepCopyInto(out *RouterResourceStatus) { +func (in *ServerResourceStatus) DeepCopyInto(out *ServerResourceStatus) { *out = *in + if in.ServerGroups != nil { + in, out := &in.ServerGroups, &out.ServerGroups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]ServerVolumeStatus, len(*in)) + copy(*out, *in) + } + if in.Interfaces != nil { + in, out := &in.Interfaces, &out.Interfaces + *out = make([]ServerInterfaceStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]string, len(*in)) copy(*out, *in) } - if in.AdminStateUp != nil { - in, out := &in.AdminStateUp, &out.AdminStateUp - *out = new(bool) + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make([]ServerMetadataStatus, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerResourceStatus. +func (in *ServerResourceStatus) DeepCopy() *ServerResourceStatus { + if in == nil { + return nil + } + out := new(ServerResourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerSchedulerHints) DeepCopyInto(out *ServerSchedulerHints) { + *out = *in + if in.ServerGroupRef != nil { + in, out := &in.ServerGroupRef, &out.ServerGroupRef + *out = new(KubernetesNameRef) **out = **in } - if in.ExternalGateways != nil { - in, out := &in.ExternalGateways, &out.ExternalGateways - *out = make([]ExternalGatewayStatus, len(*in)) + if in.DifferentHostServerRefs != nil { + in, out := &in.DifferentHostServerRefs, &out.DifferentHostServerRefs + *out = make([]KubernetesNameRef, len(*in)) copy(*out, *in) } - if in.AvailabilityZoneHints != nil { - in, out := &in.AvailabilityZoneHints, &out.AvailabilityZoneHints + if in.SameHostServerRefs != nil { + in, out := &in.SameHostServerRefs, &out.SameHostServerRefs + *out = make([]KubernetesNameRef, len(*in)) + copy(*out, *in) + } + if in.DifferentCell != nil { + in, out := &in.DifferentCell, &out.DifferentCell *out = make([]string, len(*in)) copy(*out, *in) } + if in.BuildNearHostIP != nil { + in, out := &in.BuildNearHostIP, &out.BuildNearHostIP + *out = new(CIDR) + **out = **in + } + if in.AdditionalProperties != nil { + in, out := &in.AdditionalProperties, &out.AdditionalProperties + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterResourceStatus. -func (in *RouterResourceStatus) DeepCopy() *RouterResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerSchedulerHints. +func (in *ServerSchedulerHints) DeepCopy() *ServerSchedulerHints { if in == nil { return nil } - out := new(RouterResourceStatus) + out := new(ServerSchedulerHints) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterSpec) DeepCopyInto(out *RouterSpec) { +func (in *ServerSpec) DeepCopyInto(out *ServerSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(RouterImport) + *out = new(ServerImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(RouterResourceSpec) + *out = new(ServerResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -3449,53 +5731,97 @@ func (in *RouterSpec) DeepCopyInto(out *RouterSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterSpec. -func (in *RouterSpec) DeepCopy() *RouterSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerSpec. +func (in *ServerSpec) DeepCopy() *ServerSpec { + if in == nil { + return nil + } + out := new(ServerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerStatus) DeepCopyInto(out *ServerStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(ServerResourceStatus) + (*in).DeepCopyInto(*out) + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerStatus. +func (in *ServerStatus) DeepCopy() *ServerStatus { + if in == nil { + return nil + } + out := new(ServerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServerVolumeSpec) DeepCopyInto(out *ServerVolumeSpec) { + *out = *in + if in.Device != nil { + in, out := &in.Device, &out.Device + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerVolumeSpec. +func (in *ServerVolumeSpec) DeepCopy() *ServerVolumeSpec { if in == nil { return nil } - out := new(RouterSpec) + out := new(ServerVolumeSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RouterStatus) DeepCopyInto(out *RouterStatus) { +func (in *ServerVolumeStatus) DeepCopyInto(out *ServerVolumeStatus) { *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ID != nil { - in, out := &in.ID, &out.ID - *out = new(string) - **out = **in - } - if in.Resource != nil { - in, out := &in.Resource, &out.Resource - *out = new(RouterResourceStatus) - (*in).DeepCopyInto(*out) - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouterStatus. -func (in *RouterStatus) DeepCopy() *RouterStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerVolumeStatus. +func (in *ServerVolumeStatus) DeepCopy() *ServerVolumeStatus { if in == nil { return nil } - out := new(RouterStatus) + out := new(ServerVolumeStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroup) DeepCopyInto(out *SecurityGroup) { +func (in *Service) DeepCopyInto(out *Service) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -3503,18 +5829,18 @@ func (in *SecurityGroup) DeepCopyInto(out *SecurityGroup) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroup. -func (in *SecurityGroup) DeepCopy() *SecurityGroup { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service. +func (in *Service) DeepCopy() *Service { if in == nil { return nil } - out := new(SecurityGroup) + out := new(Service) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SecurityGroup) DeepCopyObject() runtime.Object { +func (in *Service) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -3522,38 +5848,32 @@ func (in *SecurityGroup) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupFilter) DeepCopyInto(out *SecurityGroupFilter) { +func (in *ServiceFilter) DeepCopyInto(out *ServiceFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(OpenStackName) **out = **in } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(NeutronDescription) - **out = **in - } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef - *out = new(KubernetesNameRef) + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(string) **out = **in } - in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupFilter. -func (in *SecurityGroupFilter) DeepCopy() *SecurityGroupFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceFilter. +func (in *ServiceFilter) DeepCopy() *ServiceFilter { if in == nil { return nil } - out := new(SecurityGroupFilter) + out := new(ServiceFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupImport) DeepCopyInto(out *SecurityGroupImport) { +func (in *ServiceImport) DeepCopyInto(out *ServiceImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -3562,47 +5882,47 @@ func (in *SecurityGroupImport) DeepCopyInto(out *SecurityGroupImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(SecurityGroupFilter) + *out = new(ServiceFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupImport. -func (in *SecurityGroupImport) DeepCopy() *SecurityGroupImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceImport. +func (in *ServiceImport) DeepCopy() *ServiceImport { if in == nil { return nil } - out := new(SecurityGroupImport) + out := new(ServiceImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupList) DeepCopyInto(out *SecurityGroupList) { +func (in *ServiceList) DeepCopyInto(out *ServiceList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]SecurityGroup, len(*in)) + *out = make([]Service, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupList. -func (in *SecurityGroupList) DeepCopy() *SecurityGroupList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceList. +func (in *ServiceList) DeepCopy() *ServiceList { if in == nil { return nil } - out := new(SecurityGroupList) + out := new(ServiceList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SecurityGroupList) DeepCopyObject() runtime.Object { +func (in *ServiceList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -3610,7 +5930,7 @@ func (in *SecurityGroupList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupResourceSpec) DeepCopyInto(out *SecurityGroupResourceSpec) { +func (in *ServiceResourceSpec) DeepCopyInto(out *ServiceResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name @@ -3619,142 +5939,57 @@ func (in *SecurityGroupResourceSpec) DeepCopyInto(out *SecurityGroupResourceSpec } if in.Description != nil { in, out := &in.Description, &out.Description - *out = new(NeutronDescription) + *out = new(string) **out = **in } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } - if in.Stateful != nil { - in, out := &in.Stateful, &out.Stateful + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled *out = new(bool) **out = **in } - if in.Rules != nil { - in, out := &in.Rules, &out.Rules - *out = make([]SecurityGroupRule, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef - *out = new(KubernetesNameRef) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupResourceSpec. -func (in *SecurityGroupResourceSpec) DeepCopy() *SecurityGroupResourceSpec { - if in == nil { - return nil - } - out := new(SecurityGroupResourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupResourceStatus) DeepCopyInto(out *SecurityGroupResourceStatus) { - *out = *in - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Rules != nil { - in, out := &in.Rules, &out.Rules - *out = make([]SecurityGroupRuleStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupResourceStatus. -func (in *SecurityGroupResourceStatus) DeepCopy() *SecurityGroupResourceStatus { - if in == nil { - return nil - } - out := new(SecurityGroupResourceStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupRule) DeepCopyInto(out *SecurityGroupRule) { - *out = *in - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(NeutronDescription) - **out = **in - } - if in.Direction != nil { - in, out := &in.Direction, &out.Direction - *out = new(RuleDirection) - **out = **in - } - if in.RemoteIPPrefix != nil { - in, out := &in.RemoteIPPrefix, &out.RemoteIPPrefix - *out = new(CIDR) - **out = **in - } - if in.Protocol != nil { - in, out := &in.Protocol, &out.Protocol - *out = new(Protocol) - **out = **in - } - if in.PortRange != nil { - in, out := &in.PortRange, &out.PortRange - *out = new(PortRangeSpec) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupRule. -func (in *SecurityGroupRule) DeepCopy() *SecurityGroupRule { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceResourceSpec. +func (in *ServiceResourceSpec) DeepCopy() *ServiceResourceSpec { if in == nil { return nil } - out := new(SecurityGroupRule) + out := new(ServiceResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupRuleStatus) DeepCopyInto(out *SecurityGroupRuleStatus) { +func (in *ServiceResourceStatus) DeepCopyInto(out *ServiceResourceStatus) { *out = *in - if in.PortRange != nil { - in, out := &in.PortRange, &out.PortRange - *out = new(PortRangeStatus) + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupRuleStatus. -func (in *SecurityGroupRuleStatus) DeepCopy() *SecurityGroupRuleStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceResourceStatus. +func (in *ServiceResourceStatus) DeepCopy() *ServiceResourceStatus { if in == nil { return nil } - out := new(SecurityGroupRuleStatus) + out := new(ServiceResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupSpec) DeepCopyInto(out *SecurityGroupSpec) { +func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(SecurityGroupImport) + *out = new(ServiceImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(SecurityGroupResourceSpec) + *out = new(ServiceResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -3762,21 +5997,26 @@ func (in *SecurityGroupSpec) DeepCopyInto(out *SecurityGroupSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupSpec. -func (in *SecurityGroupSpec) DeepCopy() *SecurityGroupSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSpec. +func (in *ServiceSpec) DeepCopy() *ServiceSpec { if in == nil { return nil } - out := new(SecurityGroupSpec) + out := new(ServiceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SecurityGroupStatus) DeepCopyInto(out *SecurityGroupStatus) { +func (in *ServiceStatus) DeepCopyInto(out *ServiceStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -3792,71 +6032,27 @@ func (in *SecurityGroupStatus) DeepCopyInto(out *SecurityGroupStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(SecurityGroupResourceStatus) + *out = new(ServiceResourceStatus) (*in).DeepCopyInto(*out) } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityGroupStatus. -func (in *SecurityGroupStatus) DeepCopy() *SecurityGroupStatus { - if in == nil { - return nil - } - out := new(SecurityGroupStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Server) DeepCopyInto(out *Server) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Server. -func (in *Server) DeepCopy() *Server { - if in == nil { - return nil - } - out := new(Server) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Server) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerFilter) DeepCopyInto(out *ServerFilter) { - *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() } - in.FilterByServerTags.DeepCopyInto(&out.FilterByServerTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerFilter. -func (in *ServerFilter) DeepCopy() *ServerFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceStatus. +func (in *ServiceStatus) DeepCopy() *ServiceStatus { if in == nil { return nil } - out := new(ServerFilter) + out := new(ServiceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroup) DeepCopyInto(out *ServerGroup) { +func (in *ShareNetwork) DeepCopyInto(out *ShareNetwork) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -3864,18 +6060,18 @@ func (in *ServerGroup) DeepCopyInto(out *ServerGroup) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroup. -func (in *ServerGroup) DeepCopy() *ServerGroup { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetwork. +func (in *ShareNetwork) DeepCopy() *ShareNetwork { if in == nil { return nil } - out := new(ServerGroup) + out := new(ShareNetwork) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ServerGroup) DeepCopyObject() runtime.Object { +func (in *ShareNetwork) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -3883,27 +6079,32 @@ func (in *ServerGroup) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupFilter) DeepCopyInto(out *ServerGroupFilter) { +func (in *ShareNetworkFilter) DeepCopyInto(out *ShareNetworkFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(OpenStackName) **out = **in } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupFilter. -func (in *ServerGroupFilter) DeepCopy() *ServerGroupFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetworkFilter. +func (in *ShareNetworkFilter) DeepCopy() *ShareNetworkFilter { if in == nil { return nil } - out := new(ServerGroupFilter) + out := new(ShareNetworkFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupImport) DeepCopyInto(out *ServerGroupImport) { +func (in *ShareNetworkImport) DeepCopyInto(out *ShareNetworkImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -3912,47 +6113,47 @@ func (in *ServerGroupImport) DeepCopyInto(out *ServerGroupImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(ServerGroupFilter) + *out = new(ShareNetworkFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupImport. -func (in *ServerGroupImport) DeepCopy() *ServerGroupImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetworkImport. +func (in *ShareNetworkImport) DeepCopy() *ShareNetworkImport { if in == nil { return nil } - out := new(ServerGroupImport) + out := new(ShareNetworkImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupList) DeepCopyInto(out *ServerGroupList) { +func (in *ShareNetworkList) DeepCopyInto(out *ShareNetworkList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]ServerGroup, len(*in)) + *out = make([]ShareNetwork, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupList. -func (in *ServerGroupList) DeepCopy() *ServerGroupList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetworkList. +func (in *ShareNetworkList) DeepCopy() *ShareNetworkList { if in == nil { return nil } - out := new(ServerGroupList) + out := new(ShareNetworkList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ServerGroupList) DeepCopyObject() runtime.Object { +func (in *ShareNetworkList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -3960,96 +6161,84 @@ func (in *ServerGroupList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupResourceSpec) DeepCopyInto(out *ServerGroupResourceSpec) { +func (in *ShareNetworkResourceSpec) DeepCopyInto(out *ShareNetworkResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(OpenStackName) **out = **in } - if in.Rules != nil { - in, out := &in.Rules, &out.Rules - *out = new(ServerGroupRules) + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) **out = **in } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupResourceSpec. -func (in *ServerGroupResourceSpec) DeepCopy() *ServerGroupResourceSpec { - if in == nil { - return nil + if in.NetworkRef != nil { + in, out := &in.NetworkRef, &out.NetworkRef + *out = new(KubernetesNameRef) + **out = **in } - out := new(ServerGroupResourceSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupResourceStatus) DeepCopyInto(out *ServerGroupResourceStatus) { - *out = *in - if in.Rules != nil { - in, out := &in.Rules, &out.Rules - *out = new(ServerGroupRulesStatus) - (*in).DeepCopyInto(*out) + if in.SubnetRef != nil { + in, out := &in.SubnetRef, &out.SubnetRef + *out = new(KubernetesNameRef) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupResourceStatus. -func (in *ServerGroupResourceStatus) DeepCopy() *ServerGroupResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetworkResourceSpec. +func (in *ShareNetworkResourceSpec) DeepCopy() *ShareNetworkResourceSpec { if in == nil { return nil } - out := new(ServerGroupResourceStatus) + out := new(ShareNetworkResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupRules) DeepCopyInto(out *ServerGroupRules) { +func (in *ShareNetworkResourceStatus) DeepCopyInto(out *ShareNetworkResourceStatus) { *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupRules. -func (in *ServerGroupRules) DeepCopy() *ServerGroupRules { - if in == nil { - return nil + if in.SegmentationID != nil { + in, out := &in.SegmentationID, &out.SegmentationID + *out = new(int32) + **out = **in } - out := new(ServerGroupRules) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupRulesStatus) DeepCopyInto(out *ServerGroupRulesStatus) { - *out = *in - if in.MaxServerPerHost != nil { - in, out := &in.MaxServerPerHost, &out.MaxServerPerHost + if in.IPVersion != nil { + in, out := &in.IPVersion, &out.IPVersion *out = new(int32) **out = **in } + if in.CreatedAt != nil { + in, out := &in.CreatedAt, &out.CreatedAt + *out = (*in).DeepCopy() + } + if in.UpdatedAt != nil { + in, out := &in.UpdatedAt, &out.UpdatedAt + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupRulesStatus. -func (in *ServerGroupRulesStatus) DeepCopy() *ServerGroupRulesStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetworkResourceStatus. +func (in *ShareNetworkResourceStatus) DeepCopy() *ShareNetworkResourceStatus { if in == nil { return nil } - out := new(ServerGroupRulesStatus) + out := new(ShareNetworkResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupSpec) DeepCopyInto(out *ServerGroupSpec) { +func (in *ShareNetworkSpec) DeepCopyInto(out *ShareNetworkSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(ServerGroupImport) + *out = new(ShareNetworkImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ServerGroupResourceSpec) + *out = new(ShareNetworkResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -4057,21 +6246,26 @@ func (in *ServerGroupSpec) DeepCopyInto(out *ServerGroupSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupSpec. -func (in *ServerGroupSpec) DeepCopy() *ServerGroupSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetworkSpec. +func (in *ShareNetworkSpec) DeepCopy() *ShareNetworkSpec { if in == nil { return nil } - out := new(ServerGroupSpec) + out := new(ShareNetworkSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) { +func (in *ShareNetworkStatus) DeepCopyInto(out *ShareNetworkStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -4087,235 +6281,317 @@ func (in *ServerGroupStatus) DeepCopyInto(out *ServerGroupStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ServerGroupResourceStatus) + *out = new(ShareNetworkResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerGroupStatus. -func (in *ServerGroupStatus) DeepCopy() *ServerGroupStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShareNetworkStatus. +func (in *ShareNetworkStatus) DeepCopy() *ShareNetworkStatus { if in == nil { return nil } - out := new(ServerGroupStatus) + out := new(ShareNetworkStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerImport) DeepCopyInto(out *ServerImport) { +func (in *Subnet) DeepCopyInto(out *Subnet) { *out = *in - if in.ID != nil { - in, out := &in.ID, &out.ID - *out = new(string) + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subnet. +func (in *Subnet) DeepCopy() *Subnet { + if in == nil { + return nil + } + out := new(Subnet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Subnet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubnetFilter) DeepCopyInto(out *SubnetFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) **out = **in } - if in.Filter != nil { - in, out := &in.Filter, &out.Filter - *out = new(ServerFilter) + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.IPVersion != nil { + in, out := &in.IPVersion, &out.IPVersion + *out = new(IPVersion) + **out = **in + } + if in.GatewayIP != nil { + in, out := &in.GatewayIP, &out.GatewayIP + *out = new(IPvAny) + **out = **in + } + if in.CIDR != nil { + in, out := &in.CIDR, &out.CIDR + *out = new(CIDR) + **out = **in + } + if in.IPv6 != nil { + in, out := &in.IPv6, &out.IPv6 + *out = new(IPv6Options) (*in).DeepCopyInto(*out) } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerImport. -func (in *ServerImport) DeepCopy() *ServerImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetFilter. +func (in *SubnetFilter) DeepCopy() *SubnetFilter { if in == nil { return nil } - out := new(ServerImport) + out := new(SubnetFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerInterfaceFixedIP) DeepCopyInto(out *ServerInterfaceFixedIP) { +func (in *SubnetGateway) DeepCopyInto(out *SubnetGateway) { *out = *in + if in.IP != nil { + in, out := &in.IP, &out.IP + *out = new(IPvAny) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerInterfaceFixedIP. -func (in *ServerInterfaceFixedIP) DeepCopy() *ServerInterfaceFixedIP { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetGateway. +func (in *SubnetGateway) DeepCopy() *SubnetGateway { if in == nil { return nil } - out := new(ServerInterfaceFixedIP) + out := new(SubnetGateway) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerInterfaceStatus) DeepCopyInto(out *ServerInterfaceStatus) { +func (in *SubnetImport) DeepCopyInto(out *SubnetImport) { *out = *in - if in.FixedIPs != nil { - in, out := &in.FixedIPs, &out.FixedIPs - *out = make([]ServerInterfaceFixedIP, len(*in)) - copy(*out, *in) + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(SubnetFilter) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerInterfaceStatus. -func (in *ServerInterfaceStatus) DeepCopy() *ServerInterfaceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetImport. +func (in *SubnetImport) DeepCopy() *SubnetImport { if in == nil { return nil } - out := new(ServerInterfaceStatus) + out := new(SubnetImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerList) DeepCopyInto(out *ServerList) { +func (in *SubnetList) DeepCopyInto(out *SubnetList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Server, len(*in)) + *out = make([]Subnet, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerList. -func (in *ServerList) DeepCopy() *ServerList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetList. +func (in *SubnetList) DeepCopy() *SubnetList { if in == nil { return nil } - out := new(ServerList) + out := new(SubnetList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ServerList) DeepCopyObject() runtime.Object { +func (in *SubnetList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerPortSpec) DeepCopyInto(out *ServerPortSpec) { - *out = *in - if in.PortRef != nil { - in, out := &in.PortRef, &out.PortRef - *out = new(KubernetesNameRef) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerPortSpec. -func (in *ServerPortSpec) DeepCopy() *ServerPortSpec { - if in == nil { - return nil - } - out := new(ServerPortSpec) - in.DeepCopyInto(out) - return out + return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerResourceSpec) DeepCopyInto(out *ServerResourceSpec) { +func (in *SubnetResourceSpec) DeepCopyInto(out *SubnetResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(OpenStackName) **out = **in } - if in.UserData != nil { - in, out := &in.UserData, &out.UserData - *out = new(UserDataSpec) + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) + } + if in.AllocationPools != nil { + in, out := &in.AllocationPools, &out.AllocationPools + *out = make([]AllocationPool, len(*in)) + copy(*out, *in) + } + if in.Gateway != nil { + in, out := &in.Gateway, &out.Gateway + *out = new(SubnetGateway) (*in).DeepCopyInto(*out) } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = make([]ServerPortSpec, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.EnableDHCP != nil { + in, out := &in.EnableDHCP, &out.EnableDHCP + *out = new(bool) + **out = **in } - if in.Volumes != nil { - in, out := &in.Volumes, &out.Volumes - *out = make([]ServerVolumeSpec, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.DNSNameservers != nil { + in, out := &in.DNSNameservers, &out.DNSNameservers + *out = make([]IPvAny, len(*in)) + copy(*out, *in) } - if in.ServerGroupRef != nil { - in, out := &in.ServerGroupRef, &out.ServerGroupRef - *out = new(KubernetesNameRef) + if in.DNSPublishFixedIP != nil { + in, out := &in.DNSPublishFixedIP, &out.DNSPublishFixedIP + *out = new(bool) **out = **in } - if in.KeypairRef != nil { - in, out := &in.KeypairRef, &out.KeypairRef + if in.HostRoutes != nil { + in, out := &in.HostRoutes, &out.HostRoutes + *out = make([]HostRoute, len(*in)) + copy(*out, *in) + } + if in.IPv6 != nil { + in, out := &in.IPv6, &out.IPv6 + *out = new(IPv6Options) + (*in).DeepCopyInto(*out) + } + if in.RouterRef != nil { + in, out := &in.RouterRef, &out.RouterRef *out = new(KubernetesNameRef) **out = **in } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]ServerTag, len(*in)) - copy(*out, *in) + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerResourceSpec. -func (in *ServerResourceSpec) DeepCopy() *ServerResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResourceSpec. +func (in *SubnetResourceSpec) DeepCopy() *SubnetResourceSpec { if in == nil { return nil } - out := new(ServerResourceSpec) + out := new(SubnetResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerResourceStatus) DeepCopyInto(out *ServerResourceStatus) { +func (in *SubnetResourceStatus) DeepCopyInto(out *SubnetResourceStatus) { *out = *in - if in.ServerGroups != nil { - in, out := &in.ServerGroups, &out.ServerGroups + if in.IPVersion != nil { + in, out := &in.IPVersion, &out.IPVersion + *out = new(int32) + **out = **in + } + if in.DNSNameservers != nil { + in, out := &in.DNSNameservers, &out.DNSNameservers *out = make([]string, len(*in)) copy(*out, *in) } - if in.Volumes != nil { - in, out := &in.Volumes, &out.Volumes - *out = make([]ServerVolumeStatus, len(*in)) + if in.DNSPublishFixedIP != nil { + in, out := &in.DNSPublishFixedIP, &out.DNSPublishFixedIP + *out = new(bool) + **out = **in + } + if in.AllocationPools != nil { + in, out := &in.AllocationPools, &out.AllocationPools + *out = make([]AllocationPoolStatus, len(*in)) copy(*out, *in) } - if in.Interfaces != nil { - in, out := &in.Interfaces, &out.Interfaces - *out = make([]ServerInterfaceStatus, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } + if in.HostRoutes != nil { + in, out := &in.HostRoutes, &out.HostRoutes + *out = make([]HostRouteStatus, len(*in)) + copy(*out, *in) + } + if in.EnableDHCP != nil { + in, out := &in.EnableDHCP, &out.EnableDHCP + *out = new(bool) + **out = **in } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]string, len(*in)) copy(*out, *in) } + in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerResourceStatus. -func (in *ServerResourceStatus) DeepCopy() *ServerResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResourceStatus. +func (in *SubnetResourceStatus) DeepCopy() *SubnetResourceStatus { if in == nil { return nil } - out := new(ServerResourceStatus) + out := new(SubnetResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerSpec) DeepCopyInto(out *ServerSpec) { +func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(ServerImport) + *out = new(SubnetImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ServerResourceSpec) + *out = new(SubnetResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -4323,21 +6599,26 @@ func (in *ServerSpec) DeepCopyInto(out *ServerSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerSpec. -func (in *ServerSpec) DeepCopy() *ServerSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. +func (in *SubnetSpec) DeepCopy() *SubnetSpec { if in == nil { return nil } - out := new(ServerSpec) + out := new(SubnetSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerStatus) DeepCopyInto(out *ServerStatus) { +func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -4353,58 +6634,27 @@ func (in *ServerStatus) DeepCopyInto(out *ServerStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ServerResourceStatus) + *out = new(SubnetResourceStatus) (*in).DeepCopyInto(*out) } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerStatus. -func (in *ServerStatus) DeepCopy() *ServerStatus { - if in == nil { - return nil - } - out := new(ServerStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerVolumeSpec) DeepCopyInto(out *ServerVolumeSpec) { - *out = *in - if in.Device != nil { - in, out := &in.Device, &out.Device - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerVolumeSpec. -func (in *ServerVolumeSpec) DeepCopy() *ServerVolumeSpec { - if in == nil { - return nil + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() } - out := new(ServerVolumeSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServerVolumeStatus) DeepCopyInto(out *ServerVolumeStatus) { - *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerVolumeStatus. -func (in *ServerVolumeStatus) DeepCopy() *ServerVolumeStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetStatus. +func (in *SubnetStatus) DeepCopy() *SubnetStatus { if in == nil { return nil } - out := new(ServerVolumeStatus) + out := new(SubnetStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Service) DeepCopyInto(out *Service) { +func (in *Trunk) DeepCopyInto(out *Trunk) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -4412,18 +6662,18 @@ func (in *Service) DeepCopyInto(out *Service) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service. -func (in *Service) DeepCopy() *Service { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trunk. +func (in *Trunk) DeepCopy() *Trunk { if in == nil { return nil } - out := new(Service) + out := new(Trunk) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Service) DeepCopyObject() runtime.Object { +func (in *Trunk) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -4431,32 +6681,48 @@ func (in *Service) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceFilter) DeepCopyInto(out *ServiceFilter) { +func (in *TrunkFilter) DeepCopyInto(out *TrunkFilter) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(OpenStackName) **out = **in } - if in.Type != nil { - in, out := &in.Type, &out.Type - *out = new(string) + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(NeutronDescription) + **out = **in + } + if in.PortRef != nil { + in, out := &in.PortRef, &out.PortRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp + *out = new(bool) **out = **in } + in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceFilter. -func (in *ServiceFilter) DeepCopy() *ServiceFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkFilter. +func (in *TrunkFilter) DeepCopy() *TrunkFilter { if in == nil { return nil } - out := new(ServiceFilter) + out := new(TrunkFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceImport) DeepCopyInto(out *ServiceImport) { +func (in *TrunkImport) DeepCopyInto(out *TrunkImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -4465,47 +6731,47 @@ func (in *ServiceImport) DeepCopyInto(out *ServiceImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(ServiceFilter) + *out = new(TrunkFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceImport. -func (in *ServiceImport) DeepCopy() *ServiceImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkImport. +func (in *TrunkImport) DeepCopy() *TrunkImport { if in == nil { return nil } - out := new(ServiceImport) + out := new(TrunkImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceList) DeepCopyInto(out *ServiceList) { +func (in *TrunkList) DeepCopyInto(out *TrunkList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Service, len(*in)) + *out = make([]Trunk, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceList. -func (in *ServiceList) DeepCopy() *ServiceList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkList. +func (in *TrunkList) DeepCopy() *TrunkList { if in == nil { return nil } - out := new(ServiceList) + out := new(TrunkList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ServiceList) DeepCopyObject() runtime.Object { +func (in *TrunkList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -4513,7 +6779,7 @@ func (in *ServiceList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceResourceSpec) DeepCopyInto(out *ServiceResourceSpec) { +func (in *TrunkResourceSpec) DeepCopyInto(out *TrunkResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name @@ -4522,57 +6788,83 @@ func (in *ServiceResourceSpec) DeepCopyInto(out *ServiceResourceSpec) { } if in.Description != nil { in, out := &in.Description, &out.Description - *out = new(string) + *out = new(NeutronDescription) **out = **in } - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled + if in.ProjectRef != nil { + in, out := &in.ProjectRef, &out.ProjectRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp *out = new(bool) **out = **in } + if in.Subports != nil { + in, out := &in.Subports, &out.Subports + *out = make([]TrunkSubportSpec, len(*in)) + copy(*out, *in) + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]NeutronTag, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceResourceSpec. -func (in *ServiceResourceSpec) DeepCopy() *ServiceResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkResourceSpec. +func (in *TrunkResourceSpec) DeepCopy() *TrunkResourceSpec { if in == nil { return nil } - out := new(ServiceResourceSpec) + out := new(TrunkResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceResourceStatus) DeepCopyInto(out *ServiceResourceStatus) { +func (in *TrunkResourceStatus) DeepCopyInto(out *TrunkResourceStatus) { *out = *in - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) + if in.AdminStateUp != nil { + in, out := &in.AdminStateUp, &out.AdminStateUp *out = new(bool) **out = **in } + if in.Subports != nil { + in, out := &in.Subports, &out.Subports + *out = make([]TrunkSubportStatus, len(*in)) + copy(*out, *in) + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceResourceStatus. -func (in *ServiceResourceStatus) DeepCopy() *ServiceResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkResourceStatus. +func (in *TrunkResourceStatus) DeepCopy() *TrunkResourceStatus { if in == nil { return nil } - out := new(ServiceResourceStatus) + out := new(TrunkResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) { +func (in *TrunkSpec) DeepCopyInto(out *TrunkSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(ServiceImport) + *out = new(TrunkImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ServiceResourceSpec) + *out = new(TrunkResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -4580,21 +6872,26 @@ func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSpec. -func (in *ServiceSpec) DeepCopy() *ServiceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkSpec. +func (in *TrunkSpec) DeepCopy() *TrunkSpec { if in == nil { return nil } - out := new(ServiceSpec) + out := new(TrunkSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ServiceStatus) DeepCopyInto(out *ServiceStatus) { +func (in *TrunkStatus) DeepCopyInto(out *TrunkStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -4610,23 +6907,57 @@ func (in *ServiceStatus) DeepCopyInto(out *ServiceStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(ServiceResourceStatus) + *out = new(TrunkResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceStatus. -func (in *ServiceStatus) DeepCopy() *ServiceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkStatus. +func (in *TrunkStatus) DeepCopy() *TrunkStatus { if in == nil { return nil } - out := new(ServiceStatus) + out := new(TrunkStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Subnet) DeepCopyInto(out *Subnet) { +func (in *TrunkSubportSpec) DeepCopyInto(out *TrunkSubportSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkSubportSpec. +func (in *TrunkSubportSpec) DeepCopy() *TrunkSubportSpec { + if in == nil { + return nil + } + out := new(TrunkSubportSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrunkSubportStatus) DeepCopyInto(out *TrunkSubportStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrunkSubportStatus. +func (in *TrunkSubportStatus) DeepCopy() *TrunkSubportStatus { + if in == nil { + return nil + } + out := new(TrunkSubportStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -4634,18 +6965,18 @@ func (in *Subnet) DeepCopyInto(out *Subnet) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subnet. -func (in *Subnet) DeepCopy() *Subnet { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { if in == nil { return nil } - out := new(Subnet) + out := new(User) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Subnet) DeepCopyObject() runtime.Object { +func (in *User) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -4653,78 +6984,52 @@ func (in *Subnet) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetFilter) DeepCopyInto(out *SubnetFilter) { +func (in *UserDataSpec) DeepCopyInto(out *UserDataSpec) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in - } - if in.Description != nil { - in, out := &in.Description, &out.Description - *out = new(NeutronDescription) - **out = **in - } - if in.IPVersion != nil { - in, out := &in.IPVersion, &out.IPVersion - *out = new(IPVersion) - **out = **in - } - if in.GatewayIP != nil { - in, out := &in.GatewayIP, &out.GatewayIP - *out = new(IPvAny) - **out = **in - } - if in.CIDR != nil { - in, out := &in.CIDR, &out.CIDR - *out = new(CIDR) - **out = **in - } - if in.IPv6 != nil { - in, out := &in.IPv6, &out.IPv6 - *out = new(IPv6Options) - (*in).DeepCopyInto(*out) - } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef *out = new(KubernetesNameRef) **out = **in } - in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetFilter. -func (in *SubnetFilter) DeepCopy() *SubnetFilter { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserDataSpec. +func (in *UserDataSpec) DeepCopy() *UserDataSpec { if in == nil { return nil } - out := new(SubnetFilter) + out := new(UserDataSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetGateway) DeepCopyInto(out *SubnetGateway) { +func (in *UserFilter) DeepCopyInto(out *UserFilter) { *out = *in - if in.IP != nil { - in, out := &in.IP, &out.IP - *out = new(IPvAny) + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetGateway. -func (in *SubnetGateway) DeepCopy() *SubnetGateway { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserFilter. +func (in *UserFilter) DeepCopy() *UserFilter { if in == nil { return nil } - out := new(SubnetGateway) + out := new(UserFilter) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetImport) DeepCopyInto(out *SubnetImport) { +func (in *UserImport) DeepCopyInto(out *UserImport) { *out = *in if in.ID != nil { in, out := &in.ID, &out.ID @@ -4733,47 +7038,47 @@ func (in *SubnetImport) DeepCopyInto(out *SubnetImport) { } if in.Filter != nil { in, out := &in.Filter, &out.Filter - *out = new(SubnetFilter) + *out = new(UserFilter) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetImport. -func (in *SubnetImport) DeepCopy() *SubnetImport { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserImport. +func (in *UserImport) DeepCopy() *UserImport { if in == nil { return nil } - out := new(SubnetImport) + out := new(UserImport) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetList) DeepCopyInto(out *SubnetList) { +func (in *UserList) DeepCopyInto(out *UserList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Subnet, len(*in)) + *out = make([]User, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetList. -func (in *SubnetList) DeepCopy() *SubnetList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserList. +func (in *UserList) DeepCopy() *UserList { if in == nil { return nil } - out := new(SubnetList) + out := new(UserList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SubnetList) DeepCopyObject() runtime.Object { +func (in *UserList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -4781,7 +7086,7 @@ func (in *SubnetList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetResourceSpec) DeepCopyInto(out *SubnetResourceSpec) { +func (in *UserResourceSpec) DeepCopyInto(out *UserResourceSpec) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name @@ -4790,133 +7095,67 @@ func (in *SubnetResourceSpec) DeepCopyInto(out *SubnetResourceSpec) { } if in.Description != nil { in, out := &in.Description, &out.Description - *out = new(NeutronDescription) + *out = new(string) **out = **in } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]NeutronTag, len(*in)) - copy(*out, *in) - } - if in.AllocationPools != nil { - in, out := &in.AllocationPools, &out.AllocationPools - *out = make([]AllocationPool, len(*in)) - copy(*out, *in) - } - if in.Gateway != nil { - in, out := &in.Gateway, &out.Gateway - *out = new(SubnetGateway) - (*in).DeepCopyInto(*out) - } - if in.EnableDHCP != nil { - in, out := &in.EnableDHCP, &out.EnableDHCP - *out = new(bool) + if in.DomainRef != nil { + in, out := &in.DomainRef, &out.DomainRef + *out = new(KubernetesNameRef) **out = **in } - if in.DNSNameservers != nil { - in, out := &in.DNSNameservers, &out.DNSNameservers - *out = make([]IPvAny, len(*in)) - copy(*out, *in) - } - if in.DNSPublishFixedIP != nil { - in, out := &in.DNSPublishFixedIP, &out.DNSPublishFixedIP - *out = new(bool) + if in.DefaultProjectRef != nil { + in, out := &in.DefaultProjectRef, &out.DefaultProjectRef + *out = new(KubernetesNameRef) **out = **in } - if in.HostRoutes != nil { - in, out := &in.HostRoutes, &out.HostRoutes - *out = make([]HostRoute, len(*in)) - copy(*out, *in) - } - if in.IPv6 != nil { - in, out := &in.IPv6, &out.IPv6 - *out = new(IPv6Options) - (*in).DeepCopyInto(*out) - } - if in.RouterRef != nil { - in, out := &in.RouterRef, &out.RouterRef - *out = new(KubernetesNameRef) + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) **out = **in } - if in.ProjectRef != nil { - in, out := &in.ProjectRef, &out.ProjectRef + if in.PasswordRef != nil { + in, out := &in.PasswordRef, &out.PasswordRef *out = new(KubernetesNameRef) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResourceSpec. -func (in *SubnetResourceSpec) DeepCopy() *SubnetResourceSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserResourceSpec. +func (in *UserResourceSpec) DeepCopy() *UserResourceSpec { if in == nil { return nil } - out := new(SubnetResourceSpec) + out := new(UserResourceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetResourceStatus) DeepCopyInto(out *SubnetResourceStatus) { +func (in *UserResourceStatus) DeepCopyInto(out *UserResourceStatus) { *out = *in - if in.IPVersion != nil { - in, out := &in.IPVersion, &out.IPVersion - *out = new(int32) - **out = **in - } - if in.DNSNameservers != nil { - in, out := &in.DNSNameservers, &out.DNSNameservers - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.DNSPublishFixedIP != nil { - in, out := &in.DNSPublishFixedIP, &out.DNSPublishFixedIP - *out = new(bool) - **out = **in - } - if in.AllocationPools != nil { - in, out := &in.AllocationPools, &out.AllocationPools - *out = make([]AllocationPoolStatus, len(*in)) - copy(*out, *in) - } - if in.HostRoutes != nil { - in, out := &in.HostRoutes, &out.HostRoutes - *out = make([]HostRouteStatus, len(*in)) - copy(*out, *in) - } - if in.EnableDHCP != nil { - in, out := &in.EnableDHCP, &out.EnableDHCP - *out = new(bool) - **out = **in - } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) - } - in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetResourceStatus. -func (in *SubnetResourceStatus) DeepCopy() *SubnetResourceStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserResourceStatus. +func (in *UserResourceStatus) DeepCopy() *UserResourceStatus { if in == nil { return nil } - out := new(SubnetResourceStatus) + out := new(UserResourceStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { +func (in *UserSpec) DeepCopyInto(out *UserSpec) { *out = *in if in.Import != nil { in, out := &in.Import, &out.Import - *out = new(SubnetImport) + *out = new(UserImport) (*in).DeepCopyInto(*out) } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(SubnetResourceSpec) + *out = new(UserResourceSpec) (*in).DeepCopyInto(*out) } if in.ManagedOptions != nil { @@ -4924,21 +7163,26 @@ func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetSpec. -func (in *SubnetSpec) DeepCopy() *SubnetSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserSpec. +func (in *UserSpec) DeepCopy() *UserSpec { if in == nil { return nil } - out := new(SubnetSpec) + out := new(UserSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { +func (in *UserStatus) DeepCopyInto(out *UserStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -4954,37 +7198,21 @@ func (in *SubnetStatus) DeepCopyInto(out *SubnetStatus) { } if in.Resource != nil { in, out := &in.Resource, &out.Resource - *out = new(SubnetResourceStatus) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetStatus. -func (in *SubnetStatus) DeepCopy() *SubnetStatus { - if in == nil { - return nil - } - out := new(SubnetStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UserDataSpec) DeepCopyInto(out *UserDataSpec) { - *out = *in - if in.SecretRef != nil { - in, out := &in.SecretRef, &out.SecretRef - *out = new(KubernetesNameRef) + *out = new(UserResourceStatus) **out = **in } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserDataSpec. -func (in *UserDataSpec) DeepCopy() *UserDataSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserStatus. +func (in *UserStatus) DeepCopy() *UserStatus { if in == nil { return nil } - out := new(UserDataSpec) + out := new(UserStatus) in.DeepCopyInto(out) return out } @@ -5175,6 +7403,11 @@ func (in *VolumeResourceSpec) DeepCopyInto(out *VolumeResourceSpec) { *out = make([]VolumeMetadata, len(*in)) copy(*out, *in) } + if in.ImageRef != nil { + in, out := &in.ImageRef, &out.ImageRef + *out = new(KubernetesNameRef) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeResourceSpec. @@ -5260,6 +7493,11 @@ func (in *VolumeSpec) DeepCopyInto(out *VolumeSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } @@ -5293,6 +7531,10 @@ func (in *VolumeStatus) DeepCopyInto(out *VolumeStatus) { *out = new(VolumeResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeStatus. @@ -5527,6 +7769,11 @@ func (in *VolumeTypeSpec) DeepCopyInto(out *VolumeTypeSpec) { *out = new(ManagedOptions) **out = **in } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } out.CloudCredentialsRef = in.CloudCredentialsRef } @@ -5560,6 +7807,10 @@ func (in *VolumeTypeStatus) DeepCopyInto(out *VolumeTypeStatus) { *out = new(VolumeTypeResourceStatus) (*in).DeepCopyInto(*out) } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeTypeStatus. diff --git a/api/v1alpha1/zz_generated.domain-resource.go b/api/v1alpha1/zz_generated.domain-resource.go index 60b3357d6..7e42102bb 100644 --- a/api/v1alpha1/zz_generated.domain-resource.go +++ b/api/v1alpha1/zz_generated.domain-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type DomainImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type DomainSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // DomainStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type DomainStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *DomainResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Domain{} @@ -135,8 +152,8 @@ type Domain struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec DomainSpec `json:"spec,omitempty"` + // +required + Spec DomainSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.endpoint-resource.go b/api/v1alpha1/zz_generated.endpoint-resource.go new file mode 100644 index 000000000..125d1515f --- /dev/null +++ b/api/v1alpha1/zz_generated.endpoint-resource.go @@ -0,0 +1,194 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EndpointImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type EndpointImport struct { + // id contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:Format:=uuid + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *EndpointFilter `json:"filter,omitempty"` +} + +// EndpointSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type EndpointSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *EndpointImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *EndpointResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// EndpointStatus defines the observed state of an ORC resource. +type EndpointStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *EndpointResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &Endpoint{} + +func (i *Endpoint) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// Endpoint is the Schema for an ORC resource. +type Endpoint struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec EndpointSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status EndpointStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// EndpointList contains a list of Endpoint. +type EndpointList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of Endpoint. + // +required + Items []Endpoint `json:"items"` +} + +func (l *EndpointList) GetItems() []Endpoint { + return l.Items +} + +func init() { + SchemeBuilder.Register(&Endpoint{}, &EndpointList{}) +} + +func (i *Endpoint) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &Endpoint{} diff --git a/api/v1alpha1/zz_generated.flavor-resource.go b/api/v1alpha1/zz_generated.flavor-resource.go index 6577cfb64..038895f18 100644 --- a/api/v1alpha1/zz_generated.flavor-resource.go +++ b/api/v1alpha1/zz_generated.flavor-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type FlavorImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type FlavorSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // FlavorStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type FlavorStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *FlavorResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Flavor{} @@ -135,8 +152,8 @@ type Flavor struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec FlavorSpec `json:"spec,omitempty"` + // +required + Spec FlavorSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.floatingip-resource.go b/api/v1alpha1/zz_generated.floatingip-resource.go index ec90dd026..5d74a7166 100644 --- a/api/v1alpha1/zz_generated.floatingip-resource.go +++ b/api/v1alpha1/zz_generated.floatingip-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type FloatingIPImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type FloatingIPSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // FloatingIPStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type FloatingIPStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *FloatingIPResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &FloatingIP{} @@ -136,8 +153,8 @@ type FloatingIP struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec FloatingIPSpec `json:"spec,omitempty"` + // +required + Spec FloatingIPSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.group-resource.go b/api/v1alpha1/zz_generated.group-resource.go index c93a74b88..cb84a30e5 100644 --- a/api/v1alpha1/zz_generated.group-resource.go +++ b/api/v1alpha1/zz_generated.group-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type GroupImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type GroupSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // GroupStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type GroupStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *GroupResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Group{} @@ -135,8 +152,8 @@ type Group struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec GroupSpec `json:"spec,omitempty"` + // +required + Spec GroupSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.image-resource.go b/api/v1alpha1/zz_generated.image-resource.go index 41e5785f1..fb1f5633a 100644 --- a/api/v1alpha1/zz_generated.image-resource.go +++ b/api/v1alpha1/zz_generated.image-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type ImageImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -75,9 +76,17 @@ type ImageSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // ImageStatus defines the observed state of an ORC resource. @@ -105,6 +114,7 @@ type ImageStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` @@ -112,6 +122,13 @@ type ImageStatus struct { // +optional Resource *ImageResourceStatus `json:"resource,omitempty"` + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` + ImageStatusExtra `json:",inline"` } @@ -138,8 +155,8 @@ type Image struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec ImageSpec `json:"spec,omitempty"` + // +required + Spec ImageSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.keypair-resource.go b/api/v1alpha1/zz_generated.keypair-resource.go index e0e39301a..cbd363f69 100644 --- a/api/v1alpha1/zz_generated.keypair-resource.go +++ b/api/v1alpha1/zz_generated.keypair-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,8 +30,9 @@ type KeyPairImport struct { // the resource name as the unique identifier, not a UUID. // When specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:MaxLength:=1024 // +optional - ID *string `json:"id,omitempty"` + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type KeyPairSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // KeyPairStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type KeyPairStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *KeyPairResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &KeyPair{} @@ -135,8 +152,8 @@ type KeyPair struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec KeyPairSpec `json:"spec,omitempty"` + // +required + Spec KeyPairSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.network-resource.go b/api/v1alpha1/zz_generated.network-resource.go index bc5a017b1..17faf4f1c 100644 --- a/api/v1alpha1/zz_generated.network-resource.go +++ b/api/v1alpha1/zz_generated.network-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type NetworkImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type NetworkSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // NetworkStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type NetworkStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *NetworkResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Network{} @@ -135,8 +152,8 @@ type Network struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec NetworkSpec `json:"spec,omitempty"` + // +required + Spec NetworkSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.port-resource.go b/api/v1alpha1/zz_generated.port-resource.go index 631ec707b..4559d0860 100644 --- a/api/v1alpha1/zz_generated.port-resource.go +++ b/api/v1alpha1/zz_generated.port-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type PortImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type PortSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // PortStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type PortStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *PortResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Port{} @@ -136,8 +153,8 @@ type Port struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec PortSpec `json:"spec,omitempty"` + // +required + Spec PortSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.project-resource.go b/api/v1alpha1/zz_generated.project-resource.go index ffd861f4f..3498d1632 100644 --- a/api/v1alpha1/zz_generated.project-resource.go +++ b/api/v1alpha1/zz_generated.project-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type ProjectImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type ProjectSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // ProjectStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type ProjectStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *ProjectResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Project{} @@ -135,8 +152,8 @@ type Project struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec ProjectSpec `json:"spec,omitempty"` + // +required + Spec ProjectSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.role-resource.go b/api/v1alpha1/zz_generated.role-resource.go index 6161c0421..36a390527 100644 --- a/api/v1alpha1/zz_generated.role-resource.go +++ b/api/v1alpha1/zz_generated.role-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type RoleImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type RoleSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // RoleStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type RoleStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *RoleResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Role{} @@ -135,8 +152,8 @@ type Role struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec RoleSpec `json:"spec,omitempty"` + // +required + Spec RoleSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.roleassignment-resource.go b/api/v1alpha1/zz_generated.roleassignment-resource.go new file mode 100644 index 000000000..34b3277d4 --- /dev/null +++ b/api/v1alpha1/zz_generated.roleassignment-resource.go @@ -0,0 +1,180 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// RoleAssignmentImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +type RoleAssignmentImport struct { + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *RoleAssignmentFilter `json:"filter,omitempty"` +} + +// RoleAssignmentSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type RoleAssignmentSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *RoleAssignmentImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *RoleAssignmentResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// RoleAssignmentStatus defines the observed state of an ORC resource. +type RoleAssignmentStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *RoleAssignmentResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &RoleAssignment{} + +func (i *RoleAssignment) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// RoleAssignment is the Schema for an ORC resource. +type RoleAssignment struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec RoleAssignmentSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status RoleAssignmentStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// RoleAssignmentList contains a list of RoleAssignment. +type RoleAssignmentList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of RoleAssignment. + // +required + Items []RoleAssignment `json:"items"` +} + +func (l *RoleAssignmentList) GetItems() []RoleAssignment { + return l.Items +} + +func init() { + SchemeBuilder.Register(&RoleAssignment{}, &RoleAssignmentList{}) +} + +func (i *RoleAssignment) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &RoleAssignment{} diff --git a/api/v1alpha1/zz_generated.router-resource.go b/api/v1alpha1/zz_generated.router-resource.go index 45ca8887c..c901b07e2 100644 --- a/api/v1alpha1/zz_generated.router-resource.go +++ b/api/v1alpha1/zz_generated.router-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type RouterImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type RouterSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // RouterStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type RouterStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *RouterResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Router{} @@ -135,8 +152,8 @@ type Router struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec RouterSpec `json:"spec,omitempty"` + // +required + Spec RouterSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.securitygroup-resource.go b/api/v1alpha1/zz_generated.securitygroup-resource.go index 33f221ec0..31192086d 100644 --- a/api/v1alpha1/zz_generated.securitygroup-resource.go +++ b/api/v1alpha1/zz_generated.securitygroup-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type SecurityGroupImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type SecurityGroupSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // SecurityGroupStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type SecurityGroupStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *SecurityGroupResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &SecurityGroup{} @@ -135,8 +152,8 @@ type SecurityGroup struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec SecurityGroupSpec `json:"spec,omitempty"` + // +required + Spec SecurityGroupSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.server-resource.go b/api/v1alpha1/zz_generated.server-resource.go index 347cd2159..401a82819 100644 --- a/api/v1alpha1/zz_generated.server-resource.go +++ b/api/v1alpha1/zz_generated.server-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type ServerImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type ServerSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // ServerStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type ServerStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *ServerResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Server{} @@ -135,8 +152,8 @@ type Server struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec ServerSpec `json:"spec,omitempty"` + // +required + Spec ServerSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.servergroup-resource.go b/api/v1alpha1/zz_generated.servergroup-resource.go index 6bc16a63a..8a36d393f 100644 --- a/api/v1alpha1/zz_generated.servergroup-resource.go +++ b/api/v1alpha1/zz_generated.servergroup-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type ServerGroupImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type ServerGroupSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // ServerGroupStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type ServerGroupStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *ServerGroupResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &ServerGroup{} @@ -135,8 +152,8 @@ type ServerGroup struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec ServerGroupSpec `json:"spec,omitempty"` + // +required + Spec ServerGroupSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.service-resource.go b/api/v1alpha1/zz_generated.service-resource.go index 93faf35ca..b55800b06 100644 --- a/api/v1alpha1/zz_generated.service-resource.go +++ b/api/v1alpha1/zz_generated.service-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type ServiceImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type ServiceSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // ServiceStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type ServiceStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *ServiceResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Service{} @@ -135,8 +152,8 @@ type Service struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec ServiceSpec `json:"spec,omitempty"` + // +required + Spec ServiceSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.sharenetwork-resource.go b/api/v1alpha1/zz_generated.sharenetwork-resource.go new file mode 100644 index 000000000..ef15d712e --- /dev/null +++ b/api/v1alpha1/zz_generated.sharenetwork-resource.go @@ -0,0 +1,194 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ShareNetworkImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type ShareNetworkImport struct { + // id contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:Format:=uuid + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *ShareNetworkFilter `json:"filter,omitempty"` +} + +// ShareNetworkSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type ShareNetworkSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *ShareNetworkImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *ShareNetworkResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// ShareNetworkStatus defines the observed state of an ORC resource. +type ShareNetworkStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *ShareNetworkResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &ShareNetwork{} + +func (i *ShareNetwork) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// ShareNetwork is the Schema for an ORC resource. +type ShareNetwork struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec ShareNetworkSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status ShareNetworkStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ShareNetworkList contains a list of ShareNetwork. +type ShareNetworkList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of ShareNetwork. + // +required + Items []ShareNetwork `json:"items"` +} + +func (l *ShareNetworkList) GetItems() []ShareNetwork { + return l.Items +} + +func init() { + SchemeBuilder.Register(&ShareNetwork{}, &ShareNetworkList{}) +} + +func (i *ShareNetwork) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &ShareNetwork{} diff --git a/api/v1alpha1/zz_generated.subnet-resource.go b/api/v1alpha1/zz_generated.subnet-resource.go index 072cbc307..64e115cbc 100644 --- a/api/v1alpha1/zz_generated.subnet-resource.go +++ b/api/v1alpha1/zz_generated.subnet-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type SubnetImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type SubnetSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // SubnetStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type SubnetStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *SubnetResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Subnet{} @@ -135,8 +152,8 @@ type Subnet struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec SubnetSpec `json:"spec,omitempty"` + // +required + Spec SubnetSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.trunk-resource.go b/api/v1alpha1/zz_generated.trunk-resource.go new file mode 100644 index 000000000..f06f78ebb --- /dev/null +++ b/api/v1alpha1/zz_generated.trunk-resource.go @@ -0,0 +1,194 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TrunkImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type TrunkImport struct { + // id contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:Format:=uuid + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *TrunkFilter `json:"filter,omitempty"` +} + +// TrunkSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type TrunkSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *TrunkImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *TrunkResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// TrunkStatus defines the observed state of an ORC resource. +type TrunkStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *TrunkResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &Trunk{} + +func (i *Trunk) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// Trunk is the Schema for an ORC resource. +type Trunk struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec TrunkSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status TrunkStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// TrunkList contains a list of Trunk. +type TrunkList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of Trunk. + // +required + Items []Trunk `json:"items"` +} + +func (l *TrunkList) GetItems() []Trunk { + return l.Items +} + +func init() { + SchemeBuilder.Register(&Trunk{}, &TrunkList{}) +} + +func (i *Trunk) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &Trunk{} diff --git a/api/v1alpha1/zz_generated.user-resource.go b/api/v1alpha1/zz_generated.user-resource.go new file mode 100644 index 000000000..05da64833 --- /dev/null +++ b/api/v1alpha1/zz_generated.user-resource.go @@ -0,0 +1,194 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// UserImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type UserImport struct { + // id contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:Format:=uuid + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *UserFilter `json:"filter,omitempty"` +} + +// UserSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type UserSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *UserImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *UserResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// UserStatus defines the observed state of an ORC resource. +type UserStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *UserResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &User{} + +func (i *User) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// User is the Schema for an ORC resource. +type User struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec UserSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status UserStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// UserList contains a list of User. +type UserList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of User. + // +required + Items []User `json:"items"` +} + +func (l *UserList) GetItems() []User { + return l.Items +} + +func init() { + SchemeBuilder.Register(&User{}, &UserList{}) +} + +func (i *User) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &User{} diff --git a/api/v1alpha1/zz_generated.volume-resource.go b/api/v1alpha1/zz_generated.volume-resource.go index da525c450..dbacc68fa 100644 --- a/api/v1alpha1/zz_generated.volume-resource.go +++ b/api/v1alpha1/zz_generated.volume-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type VolumeImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type VolumeSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // VolumeStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type VolumeStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *VolumeResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &Volume{} @@ -135,8 +152,8 @@ type Volume struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec VolumeSpec `json:"spec,omitempty"` + // +required + Spec VolumeSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/api/v1alpha1/zz_generated.volumetype-resource.go b/api/v1alpha1/zz_generated.volumetype-resource.go index e2567a488..fb7dd9950 100644 --- a/api/v1alpha1/zz_generated.volumetype-resource.go +++ b/api/v1alpha1/zz_generated.volumetype-resource.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,10 @@ type VolumeTypeImport struct { // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter // filter contains a resource query which is expected to return a single // result. The controller will continue to retry if filter returns no @@ -74,9 +75,17 @@ type VolumeTypeSpec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // VolumeTypeStatus defines the observed state of an ORC resource. @@ -104,12 +113,20 @@ type VolumeTypeStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` // resource contains the observed state of the OpenStack resource. // +optional Resource *VolumeTypeResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } var _ ObjectWithConditions = &VolumeType{} @@ -135,8 +152,8 @@ type VolumeType struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec VolumeTypeSpec `json:"spec,omitempty"` + // +required + Spec VolumeTypeSpec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 293aa2bab..6f759c2e5 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -27,7 +27,10 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/addressscope" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/applicationcredential" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/domain" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/endpoint" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/flavor" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/floatingip" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" @@ -38,13 +41,17 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/port" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/project" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/role" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/roleassignment" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/router" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/routerinterface" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/securitygroup" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/server" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/servergroup" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/service" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/sharenetwork" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/subnet" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/trunk" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/user" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/volume" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/volumetype" internalmanager "github.com/k-orc/openstack-resource-controller/v2/internal/manager" @@ -75,6 +82,9 @@ func main() { flag.IntVar(&orcOpts.ScopeCacheMaxSize, "scope-cache-max-size", 10, "The maximum credentials count the operator should keep in cache. "+ "Setting this value to 0 means no cache.") + flag.DurationVar(&orcOpts.DefaultResyncPeriod, "default-resync-period", 0, + "Default resync period for all resources. Set to 0 to disable. "+ + "Can be overridden per-resource via spec.resyncPeriod.") flag.StringVar(&defaultCACertsPath, "default-ca-certs", "", "The path to a PEM-encoded CA Certificate file to supply as default for OpenStack API requests.") flag.Func("namespace", "A namespace that the controller watches to reconcile ORC objects. "+ @@ -107,25 +117,32 @@ func main() { scopeFactory := scope.NewFactory(orcOpts.ScopeCacheMaxSize, caCerts) controllers := []interfaces.Controller{ + addressscope.New(scopeFactory), + applicationcredential.New(scopeFactory), + endpoint.New(scopeFactory), image.New(scopeFactory), network.New(scopeFactory), subnet.New(scopeFactory), router.New(scopeFactory), routerinterface.New(scopeFactory), port.New(scopeFactory), + trunk.New(scopeFactory), floatingip.New(scopeFactory), flavor.New(scopeFactory), securitygroup.New(scopeFactory), server.New(scopeFactory), servergroup.New(scopeFactory), project.New(scopeFactory), + user.New(scopeFactory), volume.New(scopeFactory), volumetype.New(scopeFactory), domain.New(scopeFactory), service.New(scopeFactory), + sharenetwork.New(scopeFactory), keypair.New(scopeFactory), group.New(scopeFactory), role.New(scopeFactory), + roleassignment.New(scopeFactory), } restConfig := ctrl.GetConfigOrDie() diff --git a/cmd/models-schema/zz_generated.openapi.go b/cmd/models-schema/zz_generated.openapi.go index 8eab33c2d..29d2fa1b1 100644 --- a/cmd/models-schema/zz_generated.openapi.go +++ b/cmd/models-schema/zz_generated.openapi.go @@ -2,7 +2,7 @@ // +build !ignore_autogenerated /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,198 +30,267 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Address": schema_openstack_resource_controller_v2_api_v1alpha1_Address(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPool": schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPool(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPoolStatus": schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPoolStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPair": schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPair(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPairStatus": schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPairStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference": schema_openstack_resource_controller_v2_api_v1alpha1_CloudCredentialsReference(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Domain": schema_openstack_resource_controller_v2_api_v1alpha1_Domain(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainFilter": schema_openstack_resource_controller_v2_api_v1alpha1_DomainFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainImport": schema_openstack_resource_controller_v2_api_v1alpha1_DomainImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainList": schema_openstack_resource_controller_v2_api_v1alpha1_DomainList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainSpec": schema_openstack_resource_controller_v2_api_v1alpha1_DomainSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainStatus": schema_openstack_resource_controller_v2_api_v1alpha1_DomainStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGateway": schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGateway(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGatewayStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGatewayStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FilterByKeystoneTags": schema_openstack_resource_controller_v2_api_v1alpha1_FilterByKeystoneTags(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FilterByNeutronTags": schema_openstack_resource_controller_v2_api_v1alpha1_FilterByNeutronTags(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FilterByServerTags": schema_openstack_resource_controller_v2_api_v1alpha1_FilterByServerTags(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FixedIPStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FixedIPStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Flavor": schema_openstack_resource_controller_v2_api_v1alpha1_Flavor(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorFilter": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorImport": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorList": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIP": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIP(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPFilter": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPImport": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPList": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Group": schema_openstack_resource_controller_v2_api_v1alpha1_Group(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupFilter": schema_openstack_resource_controller_v2_api_v1alpha1_GroupFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupImport": schema_openstack_resource_controller_v2_api_v1alpha1_GroupImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupList": schema_openstack_resource_controller_v2_api_v1alpha1_GroupList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupSpec": schema_openstack_resource_controller_v2_api_v1alpha1_GroupSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupStatus": schema_openstack_resource_controller_v2_api_v1alpha1_GroupStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRoute": schema_openstack_resource_controller_v2_api_v1alpha1_HostRoute(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRouteStatus": schema_openstack_resource_controller_v2_api_v1alpha1_HostRouteStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options": schema_openstack_resource_controller_v2_api_v1alpha1_IPv6Options(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Image": schema_openstack_resource_controller_v2_api_v1alpha1_Image(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContent": schema_openstack_resource_controller_v2_api_v1alpha1_ImageContent(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContentSourceDownload": schema_openstack_resource_controller_v2_api_v1alpha1_ImageContentSourceDownload(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ImageFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash": schema_openstack_resource_controller_v2_api_v1alpha1_ImageHash(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageImport": schema_openstack_resource_controller_v2_api_v1alpha1_ImageImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageList": schema_openstack_resource_controller_v2_api_v1alpha1_ImageList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageProperties": schema_openstack_resource_controller_v2_api_v1alpha1_ImageProperties(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesHardware": schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesHardware(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesOperatingSystem": schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesOperatingSystem(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ImageSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatusExtra": schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatusExtra(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPair": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPair(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairFilter": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairImport": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairList": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairSpec": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairStatus": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions": schema_openstack_resource_controller_v2_api_v1alpha1_ManagedOptions(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Network": schema_openstack_resource_controller_v2_api_v1alpha1_Network(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkFilter": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkImport": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkList": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkSpec": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkStatus": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NeutronStatusMetadata": schema_openstack_resource_controller_v2_api_v1alpha1_NeutronStatusMetadata(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Port": schema_openstack_resource_controller_v2_api_v1alpha1_Port(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortFilter": schema_openstack_resource_controller_v2_api_v1alpha1_PortFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortImport": schema_openstack_resource_controller_v2_api_v1alpha1_PortImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortList": schema_openstack_resource_controller_v2_api_v1alpha1_PortList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortSpec": schema_openstack_resource_controller_v2_api_v1alpha1_PortSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortStatus": schema_openstack_resource_controller_v2_api_v1alpha1_PortStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Project": schema_openstack_resource_controller_v2_api_v1alpha1_Project(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectImport": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectList": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role": schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RoleFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleImport": schema_openstack_resource_controller_v2_api_v1alpha1_RoleImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleList": schema_openstack_resource_controller_v2_api_v1alpha1_RoleList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RoleSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RoleStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Router": schema_openstack_resource_controller_v2_api_v1alpha1_Router(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RouterFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterImport": schema_openstack_resource_controller_v2_api_v1alpha1_RouterImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterface": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterface(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceList": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterList": schema_openstack_resource_controller_v2_api_v1alpha1_RouterList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RouterSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RouterStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroup": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroup(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupFilter": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupImport": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupList": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRule": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRule(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRuleStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRuleStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Server": schema_openstack_resource_controller_v2_api_v1alpha1_Server(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ServerFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroup": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroup(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupImport": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupList": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRules": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRules(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRulesStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRulesStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerImport": schema_openstack_resource_controller_v2_api_v1alpha1_ServerImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceFixedIP": schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceFixedIP(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerList": schema_openstack_resource_controller_v2_api_v1alpha1_ServerList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerPortSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerPortSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Service": schema_openstack_resource_controller_v2_api_v1alpha1_Service(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceImport": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceList": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Subnet": schema_openstack_resource_controller_v2_api_v1alpha1_Subnet(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetFilter": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetGateway": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetGateway(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetImport": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetList": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserDataSpec": schema_openstack_resource_controller_v2_api_v1alpha1_UserDataSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Volume": schema_openstack_resource_controller_v2_api_v1alpha1_Volume(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeAttachmentStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeAttachmentStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeFilter": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeImport": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeList": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeMetadata": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeMetadata(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeMetadataStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeMetadataStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeType": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeType(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeExtraSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeExtraSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeExtraSpecStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeExtraSpecStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeFilter": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeFilter(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeImport": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeImport(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeList": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeList(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeResourceSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeResourceStatus(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeSpec(ref), - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeStatus(ref), - "k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource": schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Address": schema_openstack_resource_controller_v2_api_v1alpha1_Address(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScope": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScope(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeFilter": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeImport": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeList": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPool": schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPool(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPoolStatus": schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPoolStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPair": schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPair(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPairStatus": schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPairStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredential": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredential(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialAccessRule": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialAccessRule(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialAccessRuleStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialAccessRuleStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialImport": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialList": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialRoleStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialRoleStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference": schema_openstack_resource_controller_v2_api_v1alpha1_CloudCredentialsReference(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Domain": schema_openstack_resource_controller_v2_api_v1alpha1_Domain(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainFilter": schema_openstack_resource_controller_v2_api_v1alpha1_DomainFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainImport": schema_openstack_resource_controller_v2_api_v1alpha1_DomainImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainList": schema_openstack_resource_controller_v2_api_v1alpha1_DomainList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainSpec": schema_openstack_resource_controller_v2_api_v1alpha1_DomainSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainStatus": schema_openstack_resource_controller_v2_api_v1alpha1_DomainStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Endpoint": schema_openstack_resource_controller_v2_api_v1alpha1_Endpoint(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointFilter": schema_openstack_resource_controller_v2_api_v1alpha1_EndpointFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointImport": schema_openstack_resource_controller_v2_api_v1alpha1_EndpointImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointList": schema_openstack_resource_controller_v2_api_v1alpha1_EndpointList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_EndpointResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_EndpointResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointSpec": schema_openstack_resource_controller_v2_api_v1alpha1_EndpointSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointStatus": schema_openstack_resource_controller_v2_api_v1alpha1_EndpointStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGateway": schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGateway(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGatewayStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGatewayStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FilterByKeystoneTags": schema_openstack_resource_controller_v2_api_v1alpha1_FilterByKeystoneTags(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FilterByNeutronTags": schema_openstack_resource_controller_v2_api_v1alpha1_FilterByNeutronTags(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FilterByServerTags": schema_openstack_resource_controller_v2_api_v1alpha1_FilterByServerTags(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FixedIPStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FixedIPStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Flavor": schema_openstack_resource_controller_v2_api_v1alpha1_Flavor(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorExtraSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorExtraSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorExtraSpecStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorExtraSpecStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorFilter": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorImport": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorList": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FlavorStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIP": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIP(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPFilter": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPImport": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPList": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPSpec": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPStatus": schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Group": schema_openstack_resource_controller_v2_api_v1alpha1_Group(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupFilter": schema_openstack_resource_controller_v2_api_v1alpha1_GroupFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupImport": schema_openstack_resource_controller_v2_api_v1alpha1_GroupImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupList": schema_openstack_resource_controller_v2_api_v1alpha1_GroupList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupSpec": schema_openstack_resource_controller_v2_api_v1alpha1_GroupSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupStatus": schema_openstack_resource_controller_v2_api_v1alpha1_GroupStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostID": schema_openstack_resource_controller_v2_api_v1alpha1_HostID(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRoute": schema_openstack_resource_controller_v2_api_v1alpha1_HostRoute(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRouteStatus": schema_openstack_resource_controller_v2_api_v1alpha1_HostRouteStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options": schema_openstack_resource_controller_v2_api_v1alpha1_IPv6Options(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Image": schema_openstack_resource_controller_v2_api_v1alpha1_Image(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContent": schema_openstack_resource_controller_v2_api_v1alpha1_ImageContent(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContentSourceDownload": schema_openstack_resource_controller_v2_api_v1alpha1_ImageContentSourceDownload(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ImageFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash": schema_openstack_resource_controller_v2_api_v1alpha1_ImageHash(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageImport": schema_openstack_resource_controller_v2_api_v1alpha1_ImageImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageList": schema_openstack_resource_controller_v2_api_v1alpha1_ImageList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageProperties": schema_openstack_resource_controller_v2_api_v1alpha1_ImageProperties(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesHardware": schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesHardware(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesOperatingSystem": schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesOperatingSystem(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ImageSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatusExtra": schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatusExtra(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPair": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPair(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairFilter": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairImport": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairList": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairSpec": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairStatus": schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions": schema_openstack_resource_controller_v2_api_v1alpha1_ManagedOptions(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Network": schema_openstack_resource_controller_v2_api_v1alpha1_Network(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkFilter": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkImport": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkList": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkSpec": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkStatus": schema_openstack_resource_controller_v2_api_v1alpha1_NetworkStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NeutronStatusMetadata": schema_openstack_resource_controller_v2_api_v1alpha1_NeutronStatusMetadata(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Port": schema_openstack_resource_controller_v2_api_v1alpha1_Port(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortFilter": schema_openstack_resource_controller_v2_api_v1alpha1_PortFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortImport": schema_openstack_resource_controller_v2_api_v1alpha1_PortImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortList": schema_openstack_resource_controller_v2_api_v1alpha1_PortList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortSpec": schema_openstack_resource_controller_v2_api_v1alpha1_PortSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortStatus": schema_openstack_resource_controller_v2_api_v1alpha1_PortStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortValueSpec": schema_openstack_resource_controller_v2_api_v1alpha1_PortValueSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Project": schema_openstack_resource_controller_v2_api_v1alpha1_Project(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectImport": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectList": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role": schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignment": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignment(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentImport": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentList": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RoleFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleImport": schema_openstack_resource_controller_v2_api_v1alpha1_RoleImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleList": schema_openstack_resource_controller_v2_api_v1alpha1_RoleList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RoleSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RoleStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Router": schema_openstack_resource_controller_v2_api_v1alpha1_Router(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RouterFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterImport": schema_openstack_resource_controller_v2_api_v1alpha1_RouterImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterface": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterface(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceList": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterList": schema_openstack_resource_controller_v2_api_v1alpha1_RouterList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RouterSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RouterStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroup": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroup(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupFilter": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupImport": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupList": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRule": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRule(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRuleStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRuleStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Server": schema_openstack_resource_controller_v2_api_v1alpha1_Server(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerBootVolumeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerBootVolumeSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ServerFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroup": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroup(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupImport": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupList": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRules": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRules(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRulesStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRulesStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerImport": schema_openstack_resource_controller_v2_api_v1alpha1_ServerImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceFixedIP": schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceFixedIP(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerList": schema_openstack_resource_controller_v2_api_v1alpha1_ServerList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerMetadata": schema_openstack_resource_controller_v2_api_v1alpha1_ServerMetadata(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerMetadataStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerMetadataStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerPortSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerPortSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSchedulerHints": schema_openstack_resource_controller_v2_api_v1alpha1_ServerSchedulerHints(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Service": schema_openstack_resource_controller_v2_api_v1alpha1_Service(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceImport": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceList": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ServiceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetwork": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetwork(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkFilter": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkImport": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkList": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Subnet": schema_openstack_resource_controller_v2_api_v1alpha1_Subnet(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetFilter": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetGateway": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetGateway(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetImport": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetList": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Trunk": schema_openstack_resource_controller_v2_api_v1alpha1_Trunk(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkFilter": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkImport": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkList": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSpec": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkStatus": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSubportSpec": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkSubportSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSubportStatus": schema_openstack_resource_controller_v2_api_v1alpha1_TrunkSubportStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.User": schema_openstack_resource_controller_v2_api_v1alpha1_User(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserDataSpec": schema_openstack_resource_controller_v2_api_v1alpha1_UserDataSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserFilter": schema_openstack_resource_controller_v2_api_v1alpha1_UserFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserImport": schema_openstack_resource_controller_v2_api_v1alpha1_UserImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserList": schema_openstack_resource_controller_v2_api_v1alpha1_UserList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_UserResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_UserResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserSpec": schema_openstack_resource_controller_v2_api_v1alpha1_UserSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserStatus": schema_openstack_resource_controller_v2_api_v1alpha1_UserStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Volume": schema_openstack_resource_controller_v2_api_v1alpha1_Volume(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeAttachmentStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeAttachmentStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeFilter": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeImport": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeList": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeMetadata": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeMetadata(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeMetadataStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeMetadataStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeType": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeType(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeExtraSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeExtraSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeExtraSpecStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeExtraSpecStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeFilter": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeImport": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeList": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeList(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeSpec": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeStatus": schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeStatus(ref), + "k8s.io/api/core/v1.AWSElasticBlockStoreVolumeSource": schema_k8sio_api_core_v1_AWSElasticBlockStoreVolumeSource(ref), "k8s.io/api/core/v1.Affinity": schema_k8sio_api_core_v1_Affinity(ref), "k8s.io/api/core/v1.AppArmorProfile": schema_k8sio_api_core_v1_AppArmorProfile(ref), "k8s.io/api/core/v1.AttachedVolume": schema_k8sio_api_core_v1_AttachedVolume(ref), @@ -540,145 +609,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Address(ref common.Ref } } -func schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPool(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "start": { - SchemaProps: spec.SchemaProps{ - Description: "start is the first IP address in the allocation pool.", - Type: []string{"string"}, - Format: "", - }, - }, - "end": { - SchemaProps: spec.SchemaProps{ - Description: "end is the last IP address in the allocation pool.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"start", "end"}, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPoolStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "start": { - SchemaProps: spec.SchemaProps{ - Description: "start is the first IP address in the allocation pool.", - Type: []string{"string"}, - Format: "", - }, - }, - "end": { - SchemaProps: spec.SchemaProps{ - Description: "end is the last IP address in the allocation pool.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPair(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "ip": { - SchemaProps: spec.SchemaProps{ - Description: "ip contains an IP address which a server connected to the port can send packets with. It can be an IP Address or a CIDR (if supported by the underlying extension plugin).", - Type: []string{"string"}, - Format: "", - }, - }, - "mac": { - SchemaProps: spec.SchemaProps{ - Description: "mac contains a MAC address which a server connected to the port can send packets with. Defaults to the MAC address of the port.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"ip"}, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPairStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "ip": { - SchemaProps: spec.SchemaProps{ - Description: "ip contains an IP address which a server connected to the port can send packets with.", - Type: []string{"string"}, - Format: "", - }, - }, - "mac": { - SchemaProps: spec.SchemaProps{ - Description: "mac contains a MAC address which a server connected to the port can send packets with.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_CloudCredentialsReference(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "CloudCredentialsReference is a reference to a secret containing OpenStack credentials.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "secretName": { - SchemaProps: spec.SchemaProps{ - Description: "secretName is the name of a secret in the same namespace as the resource being provisioned. The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate.", - Type: []string{"string"}, - Format: "", - }, - }, - "cloudName": { - SchemaProps: spec.SchemaProps{ - Description: "cloudName specifies the name of the entry in the clouds.yaml file to use.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"secretName", "cloudName"}, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_Domain(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScope(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Domain is the Schema for an ORC resource.", + Description: "AddressScope is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -706,29 +641,30 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Domain(ref common.Refe SchemaProps: spec.SchemaProps{ Description: "spec specifies the desired state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ Description: "status defines the observed state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeStatus"), }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_DomainFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "DomainFilter defines an existing resource by its properties", + Description: "AddressScopeFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -738,9 +674,23 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainFilter(ref commo Format: "", }, }, - "enabled": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "enabled defines whether a domain is enabled or not. Default is true. Note: Users can only authorize against an enabled domain (and any of its projects).", + Description: "projectRef is a reference to the ORC Project which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + "ipVersion": { + SchemaProps: spec.SchemaProps{ + Description: "ipVersion is the IP protocol version.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "shared": { + SchemaProps: spec.SchemaProps{ + Description: "shared indicates whether this resource is shared across all projects or not. By default, only admin users can change set this value.", Type: []string{"boolean"}, Format: "", }, @@ -751,11 +701,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainFilter(ref commo } } -func schema_openstack_resource_controller_v2_api_v1alpha1_DomainImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "DomainImport specifies an existing resource which will be imported instead of creating a new one", + Description: "AddressScopeImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ "id": { @@ -768,22 +718,22 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainImport(ref commo "filter": { SchemaProps: spec.SchemaProps{ Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainFilter"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_DomainList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "DomainList contains a list of Domain.", + Description: "AddressScopeList contains a list of AddressScope.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -809,13 +759,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainList(ref common. }, "items": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Domain.", + Description: "items contains a list of AddressScope.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Domain"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScope"), }, }, }, @@ -826,15 +776,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainList(ref common. }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Domain", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScope", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "DomainResourceSpec contains the desired state of the resource.", + Description: "AddressScopeResourceSpec contains the desired state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -844,31 +794,40 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceSpec(ref Format: "", }, }, - "description": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "projectRef is a reference to the ORC Project which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, - "enabled": { + "ipVersion": { SchemaProps: spec.SchemaProps{ - Description: "enabled defines whether a domain is enabled or not. Default is true. Note: Users can only authorize against an enabled domain (and any of its projects).", + Description: "ipVersion is the IP protocol version.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "shared": { + SchemaProps: spec.SchemaProps{ + Description: "shared indicates whether this resource is shared across all projects or not. By default, only admin users can change set this value. We can't unshared a shared address scope; Neutron enforces this.", Type: []string{"boolean"}, Format: "", }, }, }, + Required: []string{"ipVersion"}, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "DomainResourceStatus represents the observed state of the resource.", + Description: "AddressScopeResourceStatus represents the observed state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -878,16 +837,23 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceStatus(r Format: "", }, }, - "description": { + "projectID": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "projectID is the ID of the Project to which the resource is associated.", Type: []string{"string"}, Format: "", }, }, - "enabled": { + "ipVersion": { SchemaProps: spec.SchemaProps{ - Description: "enabled defines whether a domain is enabled or not. Default is true. Note: Users can only authorize against an enabled domain (and any of its projects).", + Description: "ipVersion is the IP protocol version.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "shared": { + SchemaProps: spec.SchemaProps{ + Description: "shared indicates whether this resource is shared across all projects or not. By default, only admin users can change set this value.", Type: []string{"boolean"}, Format: "", }, @@ -898,23 +864,23 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceStatus(r } } -func schema_openstack_resource_controller_v2_api_v1alpha1_DomainSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "DomainSpec defines the desired state of an ORC object.", + Description: "AddressScopeSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeResourceSpec"), }, }, "managementPolicy": { @@ -930,6 +896,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainSpec(ref common. Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -942,15 +914,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainSpec(ref common. }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_DomainStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AddressScopeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "DomainStatus defines the observed state of an ORC resource.", + Description: "AddressScopeStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -987,46 +959,66 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_DomainStatus(ref commo "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AddressScopeResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGateway(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPool(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "networkRef": { + "start": { SchemaProps: spec.SchemaProps{ - Description: "networkRef is a reference to the ORC Network which the external gateway is on.", + Description: "start is the first IP address in the allocation pool.", + Type: []string{"string"}, + Format: "", + }, + }, + "end": { + SchemaProps: spec.SchemaProps{ + Description: "end is the last IP address in the allocation pool.", Type: []string{"string"}, Format: "", }, }, }, - Required: []string{"networkRef"}, + Required: []string{"start", "end"}, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGatewayStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AllocationPoolStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "networkID": { + "start": { SchemaProps: spec.SchemaProps{ - Description: "networkID is the ID of the network the gateway is on.", + Description: "start is the first IP address in the allocation pool.", + Type: []string{"string"}, + Format: "", + }, + }, + "end": { + SchemaProps: spec.SchemaProps{ + Description: "end is the last IP address in the allocation pool.", Type: []string{"string"}, Format: "", }, @@ -1037,24 +1029,3731 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGatewayStatus( } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByKeystoneTags(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPair(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "ip": { + SchemaProps: spec.SchemaProps{ + Description: "ip contains an IP address which a server connected to the port can send packets with. It can be an IP Address or a CIDR (if supported by the underlying extension plugin).", + Type: []string{"string"}, + Format: "", }, + }, + "mac": { SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ + Description: "mac contains a MAC address which a server connected to the port can send packets with. Defaults to the MAC address of the port.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"ip"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_AllowedAddressPairStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "ip": { + SchemaProps: spec.SchemaProps{ + Description: "ip contains an IP address which a server connected to the port can send packets with.", + Type: []string{"string"}, + Format: "", + }, + }, + "mac": { + SchemaProps: spec.SchemaProps{ + Description: "mac contains a MAC address which a server connected to the port can send packets with.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredential(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredential is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialAccessRule(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialAccessRule defines an access rule", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "path": { + SchemaProps: spec.SchemaProps{ + Description: "path that the application credential is permitted to access", + Type: []string{"string"}, + Format: "", + }, + }, + "method": { + SchemaProps: spec.SchemaProps{ + Description: "method that the application credential is permitted to use for a given API endpoint", + Type: []string{"string"}, + Format: "", + }, + }, + "serviceRef": { + SchemaProps: spec.SchemaProps{ + Description: "serviceRef identifier for the service that the application credential is permitted to access", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialAccessRuleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the ID of this access rule", + Type: []string{"string"}, + Format: "", + }, + }, + "path": { + SchemaProps: spec.SchemaProps{ + Description: "path that the application credential is permitted to access", + Type: []string{"string"}, + Format: "", + }, + }, + "method": { + SchemaProps: spec.SchemaProps{ + Description: "method that the application credential is permitted to use for a given API endpoint", + Type: []string{"string"}, + Format: "", + }, + }, + "service": { + SchemaProps: spec.SchemaProps{ + Description: "service type identifier for the service that the application credential is permitted to access", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "userRef": { + SchemaProps: spec.SchemaProps{ + Description: "userRef is a reference to the ORC User which this resource is associated with. Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried.", + Type: []string{"string"}, + Format: "", + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"userRef"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialList contains a list of ApplicationCredential.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of ApplicationCredential.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredential"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredential", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "userRef": { + SchemaProps: spec.SchemaProps{ + Description: "userRef is a reference to the ORC User which this resource is associated with. Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried.", + Type: []string{"string"}, + Format: "", + }, + }, + "unrestricted": { + SchemaProps: spec.SchemaProps{ + Description: "unrestricted is a flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts", + Type: []string{"boolean"}, + Format: "", + }, + }, + "secretRef": { + SchemaProps: spec.SchemaProps{ + Description: "secretRef is a reference to a Secret containing the application credential secret", + Type: []string{"string"}, + Format: "", + }, + }, + "roleRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "roleRefs may only contain roles that the user has assigned on the project. If not provided, the roles assigned to the application credential will be the same as the roles in the current token.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "accessRules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "accessRules is a list of fine grained access control rules", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialAccessRule"), + }, + }, + }, + }, + }, + "expiresAt": { + SchemaProps: spec.SchemaProps{ + Description: "expiresAt is the time of expiration for the application credential. If unset, the application credential does not expire.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + Required: []string{"userRef", "secretRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialAccessRule", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the resource. Might not be unique.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "unrestricted": { + SchemaProps: spec.SchemaProps{ + Description: "unrestricted is a flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts", + Type: []string{"boolean"}, + Format: "", + }, + }, + "projectID": { + SchemaProps: spec.SchemaProps{ + Description: "projectID of the project the application credential was created for and that authentication requests using this application credential will be scoped to.", + Type: []string{"string"}, + Format: "", + }, + }, + "roles": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "roles is a list of role objects may only contain roles that the user has assigned on the project", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialRoleStatus"), + }, + }, + }, + }, + }, + "expiresAt": { + SchemaProps: spec.SchemaProps{ + Description: "expiresAt is the time of expiration for the application credential. If unset, the application credential does not expire.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "accessRules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "accessRules is a list of fine grained access control rules", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialAccessRuleStatus"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialAccessRuleStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialRoleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialRoleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of an existing role", + Type: []string{"string"}, + Format: "", + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the ID of a role", + Type: []string{"string"}, + Format: "", + }, + }, + "domainID": { + SchemaProps: spec.SchemaProps{ + Description: "domainID of the domain of this role", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ApplicationCredentialStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationCredentialStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ApplicationCredentialResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_CloudCredentialsReference(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CloudCredentialsReference is a reference to a secret containing OpenStack credentials.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "secretName": { + SchemaProps: spec.SchemaProps{ + Description: "secretName is the name of a secret in the same namespace as the resource being provisioned. The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate.", + Type: []string{"string"}, + Format: "", + }, + }, + "cloudName": { + SchemaProps: spec.SchemaProps{ + Description: "cloudName specifies the name of the entry in the clouds.yaml file to use.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"secretName", "cloudName"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_Domain(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Domain is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_DomainFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DomainFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "enabled": { + SchemaProps: spec.SchemaProps{ + Description: "enabled defines whether a domain is enabled or not. Default is true. Note: Users can only authorize against an enabled domain (and any of its projects).", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_DomainImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DomainImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_DomainList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DomainList contains a list of Domain.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of Domain.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Domain"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Domain", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DomainResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "enabled": { + SchemaProps: spec.SchemaProps{ + Description: "enabled defines whether a domain is enabled or not. Default is true. Note: Users can only authorize against an enabled domain (and any of its projects).", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_DomainResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DomainResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the resource. Might not be unique.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "enabled": { + SchemaProps: spec.SchemaProps{ + Description: "enabled defines whether a domain is enabled or not. Default is true. Note: Users can only authorize against an enabled domain (and any of its projects).", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_DomainSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DomainSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_DomainStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DomainStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.DomainResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_Endpoint(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Endpoint is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_EndpointFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "EndpointFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "interface": { + SchemaProps: spec.SchemaProps{ + Description: "interface of the existing endpoint.", + Type: []string{"string"}, + Format: "", + }, + }, + "serviceRef": { + SchemaProps: spec.SchemaProps{ + Description: "serviceRef is a reference to the ORC Service which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + "url": { + SchemaProps: spec.SchemaProps{ + Description: "url is the URL of the existing endpoint.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_EndpointImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "EndpointImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_EndpointList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "EndpointList contains a list of Endpoint.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of Endpoint.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Endpoint"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Endpoint", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_EndpointResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "EndpointResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "enabled": { + SchemaProps: spec.SchemaProps{ + Description: "enabled indicates whether the endpoint is enabled or not.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "interface": { + SchemaProps: spec.SchemaProps{ + Description: "interface indicates the visibility of the endpoint.", + Type: []string{"string"}, + Format: "", + }, + }, + "url": { + SchemaProps: spec.SchemaProps{ + Description: "url is the endpoint URL.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "serviceRef": { + SchemaProps: spec.SchemaProps{ + Description: "serviceRef is a reference to the ORC Service which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"interface", "url", "serviceRef"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_EndpointResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "EndpointResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "enabled": { + SchemaProps: spec.SchemaProps{ + Description: "enabled indicates whether the endpoint is enabled or not.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "interface": { + SchemaProps: spec.SchemaProps{ + Description: "interface indicates the visibility of the endpoint.", + Type: []string{"string"}, + Format: "", + }, + }, + "url": { + SchemaProps: spec.SchemaProps{ + Description: "url is the endpoint URL.", + Type: []string{"string"}, + Format: "", + }, + }, + "serviceID": { + SchemaProps: spec.SchemaProps{ + Description: "serviceID is the ID of the Service to which the resource is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_EndpointSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "EndpointSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_EndpointStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "EndpointStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.EndpointResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGateway(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "networkRef": { + SchemaProps: spec.SchemaProps{ + Description: "networkRef is a reference to the ORC Network which the external gateway is on.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"networkRef"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ExternalGatewayStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "networkID": { + SchemaProps: spec.SchemaProps{ + Description: "networkID is the ID of the network the gateway is on.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByKeystoneTags(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByNeutronTags(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByServerTags(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FixedIPStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "ip": { + SchemaProps: spec.SchemaProps{ + Description: "ip contains a fixed IP address assigned to the port.", + Type: []string{"string"}, + Format: "", + }, + }, + "subnetID": { + SchemaProps: spec.SchemaProps{ + Description: "subnetID is the ID of the subnet this IP is allocated from.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_Flavor(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Flavor is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorExtraSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the extraspec", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Description: "value is the value of the extraspec", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name", "value"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorExtraSpecStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the extraspec", + Type: []string{"string"}, + Format: "", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Description: "value is the value of the extraspec", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FlavorFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "ram": { + SchemaProps: spec.SchemaProps{ + Description: "ram is the memory of the flavor, measured in MB.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "vcpus": { + SchemaProps: spec.SchemaProps{ + Description: "vcpus is the number of vcpus for the flavor.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "disk": { + SchemaProps: spec.SchemaProps{ + Description: "disk is the size of the root disk in GiB.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FlavorImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FlavorList contains a list of Flavor.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of Flavor.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Flavor"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Flavor", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FlavorResourceSpec contains the desired state of a flavor", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id will be the id of the created resource. If not specified, a random UUID will be generated by OpenStack.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description contains a free form description of the flavor.", + Type: []string{"string"}, + Format: "", + }, + }, + "ram": { + SchemaProps: spec.SchemaProps{ + Description: "ram is the memory of the flavor, measured in MB.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "vcpus": { + SchemaProps: spec.SchemaProps{ + Description: "vcpus is the number of vcpus for the flavor.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "disk": { + SchemaProps: spec.SchemaProps{ + Description: "disk is the size of the root disk that will be created in GiB. If 0 the root disk will be set to exactly the size of the image used to deploy the instance. However, in this case the scheduler cannot select the compute host based on the virtual image size. Therefore, 0 should only be used for volume booted instances or for testing purposes. Volume-backed instances can be enforced for flavors with zero root disk via the os_compute_api:servers:create:zero_disk_flavor policy rule.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "swap": { + SchemaProps: spec.SchemaProps{ + Description: "swap is the size of a dedicated swap disk that will be allocated, in MiB. If 0 (the default), no dedicated swap disk will be created.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "extraSpecs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "extraSpecs is a list of key-value pairs that define extra specifications for the flavor.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorExtraSpec"), + }, + }, + }, + }, + }, + "isPublic": { + SchemaProps: spec.SchemaProps{ + Description: "isPublic flags a flavor as being available to all projects or not.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "ephemeral": { + SchemaProps: spec.SchemaProps{ + Description: "ephemeral is the size of the ephemeral disk that will be created, in GiB. Ephemeral disks may be written over on server state changes. So should only be used as a scratch space for applications that are aware of its limitations. Defaults to 0.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"ram", "vcpus", "disk"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorExtraSpec"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FlavorResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the flavor. Might not be unique.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "ram": { + SchemaProps: spec.SchemaProps{ + Description: "ram is the memory of the flavor, measured in MB.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "vcpus": { + SchemaProps: spec.SchemaProps{ + Description: "vcpus is the number of vcpus for the flavor.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "disk": { + SchemaProps: spec.SchemaProps{ + Description: "disk is the size of the root disk that will be created in GiB.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "swap": { + SchemaProps: spec.SchemaProps{ + Description: "swap is the size of a dedicated swap disk that will be allocated, in MiB.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "extraSpecs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "extraSpecs is a map of key-value pairs that define extra specifications for the flavor.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorExtraSpecStatus"), + }, + }, + }, + }, + }, + "isPublic": { + SchemaProps: spec.SchemaProps{ + Description: "isPublic flags a flavor as being available to all projects or not.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "ephemeral": { + SchemaProps: spec.SchemaProps{ + Description: "ephemeral is the size of the ephemeral disk, in GiB.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorExtraSpecStatus"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FlavorSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FlavorStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIP(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FloatingIP is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FloatingIPFilter specifies a query to select an OpenStack floatingip. At least one property must be set.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "floatingIP": { + SchemaProps: spec.SchemaProps{ + Description: "floatingIP is the floatingip address.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "floatingNetworkRef": { + SchemaProps: spec.SchemaProps{ + Description: "floatingNetworkRef is a reference to the ORC Network which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + "portRef": { + SchemaProps: spec.SchemaProps{ + Description: "portRef is a reference to the ORC Port which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + "projectRef": { + SchemaProps: spec.SchemaProps{ + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status is the status of the floatingip.", + Type: []string{"string"}, + Format: "", + }, + }, + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FloatingIPImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FloatingIPList contains a list of FloatingIP.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of FloatingIP.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIP"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIP", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FloatingIPResourceSpec contains the desired state of a floating IP", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags which will be applied to the floatingip.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "floatingNetworkRef": { + SchemaProps: spec.SchemaProps{ + Description: "floatingNetworkRef references the network to which the floatingip is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "floatingSubnetRef": { + SchemaProps: spec.SchemaProps{ + Description: "floatingSubnetRef references the subnet to which the floatingip is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "floatingIP": { + SchemaProps: spec.SchemaProps{ + Description: "floatingIP is the IP that will be assigned to the floatingip. If not set, it will be assigned automatically.", + Type: []string{"string"}, + Format: "", + }, + }, + "portRef": { + SchemaProps: spec.SchemaProps{ + Description: "portRef is a reference to the ORC Port which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + "fixedIP": { + SchemaProps: spec.SchemaProps{ + Description: "fixedIP is the IP address of the port to which the floatingip is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "projectRef": { + SchemaProps: spec.SchemaProps{ + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "floatingNetworkID": { + SchemaProps: spec.SchemaProps{ + Description: "floatingNetworkID is the ID of the network to which the floatingip is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "floatingIP": { + SchemaProps: spec.SchemaProps{ + Description: "floatingIP is the IP address of the floatingip.", + Type: []string{"string"}, + Format: "", + }, + }, + "portID": { + SchemaProps: spec.SchemaProps{ + Description: "portID is the ID of the port to which the floatingip is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "fixedIP": { + SchemaProps: spec.SchemaProps{ + Description: "fixedIP is the IP address of the port to which the floatingip is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "tenantID": { + SchemaProps: spec.SchemaProps{ + Description: "tenantID is the project owner of the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "projectID": { + SchemaProps: spec.SchemaProps{ + Description: "projectID is the project owner of the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status indicates the current status of the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "routerID": { + SchemaProps: spec.SchemaProps{ + Description: "routerID is the ID of the router to which the floatingip is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is the list of tags on the resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "createdAt": { + SchemaProps: spec.SchemaProps{ + Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "updatedAt": { + SchemaProps: spec.SchemaProps{ + Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "revisionNumber": { + SchemaProps: spec.SchemaProps{ + Description: "revisionNumber optionally set via extensions/standard-attr-revisions", + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FloatingIPSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FloatingIPStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_Group(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Group is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_GroupFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "domainRef": { + SchemaProps: spec.SchemaProps{ + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_GroupImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_GroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupList contains a list of Group.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of Group.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Group"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Group", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "domainRef": { + SchemaProps: spec.SchemaProps{ + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the resource. Might not be unique.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "domainID": { + SchemaProps: spec.SchemaProps{ + Description: "domainID is the ID of the Domain to which the resource is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_GroupSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_GroupStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_HostID(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HostID specifies how to determine the host ID for port binding. Exactly one of the fields must be set.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the literal host ID string to use for binding:host_id. This is mutually exclusive with serverRef.", + Type: []string{"string"}, + Format: "", + }, + }, + "serverRef": { + SchemaProps: spec.SchemaProps{ + Description: "serverRef is a reference to an ORC Server resource from which to retrieve the hostID for port binding. The hostID will be read from the Server's status.resource.hostID field. This is mutually exclusive with id.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_HostRoute(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "destination": { + SchemaProps: spec.SchemaProps{ + Description: "destination for the additional route.", + Type: []string{"string"}, + Format: "", + }, + }, + "nextHop": { + SchemaProps: spec.SchemaProps{ + Description: "nextHop for the additional route.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"destination", "nextHop"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_HostRouteStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "destination": { + SchemaProps: spec.SchemaProps{ + Description: "destination for the additional route.", + Type: []string{"string"}, + Format: "", + }, + }, + "nextHop": { + SchemaProps: spec.SchemaProps{ + Description: "nextHop for the additional route.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_IPv6Options(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "addressMode": { + SchemaProps: spec.SchemaProps{ + Description: "addressMode specifies mechanisms for assigning IPv6 IP addresses.", + Type: []string{"string"}, + Format: "", + }, + }, + "raMode": { + SchemaProps: spec.SchemaProps{ + Description: "raMode specifies the IPv6 router advertisement mode. It specifies whether the networking service should transmit ICMPv6 packets.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_Image(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Image is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageContent(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "containerFormat": { + SchemaProps: spec.SchemaProps{ + Description: "containerFormat is the format of the image container. qcow2 and raw images do not usually have a container. This is specified as \"bare\", which is also the default. Permitted values are ami, ari, aki, bare, compressed, ovf, ova, and docker.", + Type: []string{"string"}, + Format: "", + }, + }, + "diskFormat": { + SchemaProps: spec.SchemaProps{ + Description: "diskFormat is the format of the disk image. Normal values are \"qcow2\", or \"raw\". Glance may be configured to support others.", + Type: []string{"string"}, + Format: "", + }, + }, + "download": { + SchemaProps: spec.SchemaProps{ + Description: "download describes how to obtain image data by downloading it from a URL. Must be set when creating a managed image.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContentSourceDownload"), + }, + }, + }, + Required: []string{"diskFormat", "download"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContentSourceDownload"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageContentSourceDownload(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "url": { + SchemaProps: spec.SchemaProps{ + Description: "url containing image data", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "decompress": { + SchemaProps: spec.SchemaProps{ + Description: "decompress specifies that the source data must be decompressed with the given compression algorithm before being stored. Specifying Decompress will disable the use of Glance's web-download, as web-download cannot currently deterministically decompress downloaded content.", + Type: []string{"string"}, + Format: "", + }, + }, + "hash": { + SchemaProps: spec.SchemaProps{ + Description: "hash is a hash which will be used to verify downloaded data, i.e. before any decompression. If not specified, no hash verification will be performed. Specifying a Hash will disable the use of Glance's web-download, as web-download cannot currently deterministically verify the hash of downloaded content.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"), + }, + }, + }, + Required: []string{"url"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ImageFilter defines a Glance query", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name specifies the name of a Glance image", + Type: []string{"string"}, + Format: "", + }, + }, + "visibility": { + SchemaProps: spec.SchemaProps{ + Description: "visibility specifies the visibility of a Glance image.", + Type: []string{"string"}, + Format: "", + }, + }, + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is the list of tags on the resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageHash(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "algorithm": { + SchemaProps: spec.SchemaProps{ + Description: "algorithm is the hash algorithm used to generate value.", + Type: []string{"string"}, + Format: "", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Description: "value is the hash of the image data using Algorithm. It must be hex encoded using lowercase letters.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"algorithm", "value"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ImageImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ImageList contains a list of Image.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of Image.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Image"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Image", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageProperties(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "architecture": { + SchemaProps: spec.SchemaProps{ + Description: "architecture is the CPU architecture that must be supported by the hypervisor.", + Type: []string{"string"}, + Format: "", + }, + }, + "hypervisorType": { + SchemaProps: spec.SchemaProps{ + Description: "hypervisorType is the hypervisor type", + Type: []string{"string"}, + Format: "", + }, + }, + "minDiskGB": { + SchemaProps: spec.SchemaProps{ + Description: "minDiskGB is the minimum amount of disk space in GB that is required to boot the image", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "minMemoryMB": { + SchemaProps: spec.SchemaProps{ + Description: "minMemoryMB is the minimum amount of RAM in MB that is required to boot the image.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "hardware": { + SchemaProps: spec.SchemaProps{ + Description: "hardware is a set of properties which control the virtual hardware created by Nova.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesHardware"), + }, + }, + "operatingSystem": { + SchemaProps: spec.SchemaProps{ + Description: "operatingSystem is a set of properties that specify and influence the behavior of the operating system within the virtual machine.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesOperatingSystem"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesHardware", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesOperatingSystem"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesHardware(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "cpuSockets": { + SchemaProps: spec.SchemaProps{ + Description: "cpuSockets is the preferred number of sockets to expose to the guest", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "cpuCores": { + SchemaProps: spec.SchemaProps{ + Description: "cpuCores is the preferred number of cores to expose to the guest", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "cpuThreads": { + SchemaProps: spec.SchemaProps{ + Description: "cpuThreads is the preferred number of threads to expose to the guest", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "cpuPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "cpuPolicy is used to pin the virtual CPUs (vCPUs) of instances to the host's physical CPU cores (pCPUs). Host aggregates should be used to separate these pinned instances from unpinned instances as the latter will not respect the resourcing requirements of the former.\n\nPermitted values are shared (the default), and dedicated.\n\nshared: The guest vCPUs will be allowed to freely float across host pCPUs, albeit potentially constrained by NUMA policy.\n\ndedicated: The guest vCPUs will be strictly pinned to a set of host pCPUs. In the absence of an explicit vCPU topology request, the drivers typically expose all vCPUs as sockets with one core and one thread. When strict CPU pinning is in effect the guest CPU topology will be setup to match the topology of the CPUs to which it is pinned. This option implies an overcommit ratio of 1.0. For example, if a two vCPU guest is pinned to a single host core with two threads, then the guest will get a topology of one socket, one core, two threads.", + Type: []string{"string"}, + Format: "", + }, + }, + "cpuThreadPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "cpuThreadPolicy further refines a CPUPolicy of 'dedicated' by stating how hardware CPU threads in a simultaneous multithreading-based (SMT) architecture be used. SMT-based architectures include Intel processors with Hyper-Threading technology. In these architectures, processor cores share a number of components with one or more other cores. Cores in such architectures are commonly referred to as hardware threads, while the cores that a given core share components with are known as thread siblings.\n\nPermitted values are prefer (the default), isolate, and require.\n\nprefer: The host may or may not have an SMT architecture. Where an SMT architecture is present, thread siblings are preferred.\n\nisolate: The host must not have an SMT architecture or must emulate a non-SMT architecture. If the host does not have an SMT architecture, each vCPU is placed on a different core as expected. If the host does have an SMT architecture - that is, one or more cores have thread siblings - then each vCPU is placed on a different physical core. No vCPUs from other guests are placed on the same core. All but one thread sibling on each utilized core is therefore guaranteed to be unusable.\n\nrequire: The host must have an SMT architecture. Each vCPU is allocated on thread siblings. If the host does not have an SMT architecture, then it is not used. If the host has an SMT architecture, but not enough cores with free thread siblings are available, then scheduling fails.", + Type: []string{"string"}, + Format: "", + }, + }, + "cdromBus": { + SchemaProps: spec.SchemaProps{ + Description: "cdromBus specifies the type of disk controller to attach CD-ROM devices to.", + Type: []string{"string"}, + Format: "", + }, + }, + "diskBus": { + SchemaProps: spec.SchemaProps{ + Description: "diskBus specifies the type of disk controller to attach disk devices to.", + Type: []string{"string"}, + Format: "", + }, + }, + "scsiModel": { + SchemaProps: spec.SchemaProps{ + Description: "scsiModel enables the use of VirtIO SCSI (virtio-scsi) to provide block device access for compute instances; by default, instances use VirtIO Block (virtio-blk). VirtIO SCSI is a para-virtualized SCSI controller device that provides improved scalability and performance, and supports advanced SCSI hardware.\n\nThe only permitted value is virtio-scsi.", + Type: []string{"string"}, + Format: "", + }, + }, + "vifModel": { + SchemaProps: spec.SchemaProps{ + Description: "vifModel specifies the model of virtual network interface device to use.\n\nPermitted values are e1000, e1000e, ne2k_pci, pcnet, rtl8139, virtio, and vmxnet3.", + Type: []string{"string"}, + Format: "", + }, + }, + "rngModel": { + SchemaProps: spec.SchemaProps{ + Description: "rngModel adds a random-number generator device to the image’s instances. This image property by itself does not guarantee that a hardware RNG will be used; it expresses a preference that may or may not be satisfied depending upon Nova configuration.", + Type: []string{"string"}, + Format: "", + }, + }, + "qemuGuestAgent": { + SchemaProps: spec.SchemaProps{ + Description: "qemuGuestAgent enables QEMU guest agent.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesOperatingSystem(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "distro": { + SchemaProps: spec.SchemaProps{ + Description: "distro is the common name of the operating system distribution in lowercase.", + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Description: "version is the operating system version as specified by the distributor.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ImageResourceSpec contains the desired state of a Glance image", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created Glance image. If not specified, the name of the Image object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "protected": { + SchemaProps: spec.SchemaProps{ + Description: "protected specifies that the image is protected from deletion. If not specified, the default is false.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags which will be applied to the image. A tag has a maximum length of 255 characters.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ Default: "", Type: []string{"string"}, Format: "", @@ -1063,34 +4762,96 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByKeystoneTags(r }, }, }, - "tagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "visibility": { + SchemaProps: spec.SchemaProps{ + Description: "visibility of the image", + Type: []string{"string"}, + Format: "", + }, + }, + "properties": { + SchemaProps: spec.SchemaProps{ + Description: "properties is metadata available to consumers of the image", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageProperties"), + }, + }, + "content": { + SchemaProps: spec.SchemaProps{ + Description: "content specifies how to obtain the image content.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContent"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContent", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageProperties"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ImageResourceStatus represents the observed state of a Glance image", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the image. Might not be unique.", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status is the image status as reported by Glance", + Type: []string{"string"}, + Format: "", + }, + }, + "protected": { + SchemaProps: spec.SchemaProps{ + Description: "protected specifies that the image is protected from deletion.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "visibility": { + SchemaProps: spec.SchemaProps{ + Description: "visibility of the image", + Type: []string{"string"}, + Format: "", + }, + }, + "hash": { + SchemaProps: spec.SchemaProps{ + Description: "hash is the hash of the image data published by Glance. Note that this is a hash of the data stored internally by Glance, which will have been decompressed and potentially format converted depending on server-side configuration which is not visible to clients. It is expected that this hash will usually differ from the download hash.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"), }, + }, + "sizeB": { SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "sizeB is the size of the image data, in bytes", + Type: []string{"integer"}, + Format: "int64", }, }, - "notTags": { + "virtualSizeB": { + SchemaProps: spec.SchemaProps{ + Description: "virtualSizeB is the size of the disk the image data represents, in bytes", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Description: "tags is the list of tags on the resource.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -1103,232 +4864,368 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByKeystoneTags(r }, }, }, - "notTagsAny": { + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ImageSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ImageStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", }, }, SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), }, }, }, }, }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "downloadAttempts": { + SchemaProps: spec.SchemaProps{ + Description: "downloadAttempts is the number of times the controller has attempted to download the image contents", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByNeutronTags(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatusExtra(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "downloadAttempts": { + SchemaProps: spec.SchemaProps{ + Description: "downloadAttempts is the number of times the controller has attempted to download the image contents", + Type: []string{"integer"}, + Format: "int32", }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPair(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KeyPair is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", }, }, - "tagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", }, + }, + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, - "notTags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairSpec"), }, + }, + "status": { SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KeyPairFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing Keypair", + Type: []string{"string"}, + Format: "", }, }, - "notTagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KeyPairImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the name of an existing resource. Note: This resource uses the resource name as the unique identifier, not a UUID. When specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", }, + }, + "filter": { SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairFilter"), }, }, }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FilterByServerTags(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "KeyPairList contains a list of KeyPair.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", }, + }, + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", }, }, - "tagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, + }, + "items": { SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Description: "items contains a list of KeyPair.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPair"), }, }, }, }, }, - "notTags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPair", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KeyPairResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", }, }, - "notTagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "type specifies the type of the Keypair. Allowed values are ssh or x509. If not specified, defaults to ssh.", + Type: []string{"string"}, + Format: "", }, + }, + "publicKey": { SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "publicKey is the public key to import.", + Type: []string{"string"}, + Format: "", }, }, }, + Required: []string{"publicKey"}, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FixedIPStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "KeyPairResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "ip": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "ip contains a fixed IP address assigned to the port.", + Description: "name is a Human-readable name for the resource. Might not be unique.", Type: []string{"string"}, Format: "", }, }, - "subnetID": { + "fingerprint": { SchemaProps: spec.SchemaProps{ - Description: "subnetID is the ID of the subnet this IP is allocated from.", + Description: "fingerprint is the fingerprint of the public key", + Type: []string{"string"}, + Format: "", + }, + }, + "publicKey": { + SchemaProps: spec.SchemaProps{ + Description: "publicKey is the public key of the Keypair", + Type: []string{"string"}, + Format: "", + }, + }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "type is the type of the Keypair (ssh or x509)", Type: []string{"string"}, Format: "", }, @@ -1339,130 +5236,142 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FixedIPStatus(ref comm } } -func schema_openstack_resource_controller_v2_api_v1alpha1_Flavor(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Flavor is the Schema for an ORC resource.", + Description: "KeyPairSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "kind": { + "import": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairImport"), }, }, - "apiVersion": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", Type: []string{"string"}, Format: "", }, }, - "metadata": { + "managedOptions": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, - "spec": { + "resyncPeriod": { SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorSpec"), + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, - "status": { + "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), }, }, }, + Required: []string{"cloudCredentialsRef"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FlavorFilter defines an existing resource by its properties", + Description: "KeyPairStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", - Type: []string{"string"}, - Format: "", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, }, }, - "ram": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "ram is the memory of the flavor, measured in MB.", - Type: []string{"integer"}, - Format: "int32", + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", }, }, - "vcpus": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "vcpus is the number of vcpus for the flavor.", - Type: []string{"integer"}, - Format: "int32", + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceStatus"), }, }, - "disk": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "disk is the size of the root disk in GiB.", - Type: []string{"integer"}, - Format: "int32", + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ManagedOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FlavorImport specifies an existing resource which will be imported instead of creating a new one", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { + "onDelete": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "onDelete specifies the behaviour of the controller when the ORC object is deleted. Options are `delete` - delete the OpenStack resource; `detach` - do not delete the OpenStack resource. If not specified, the default is `delete`.", Type: []string{"string"}, Format: "", }, }, - "filter": { - SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorFilter"), - }, - }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_Network(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FlavorList contains a list of Flavor.", + Description: "Network is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -1481,369 +5390,381 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorList(ref common. }, "metadata": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", + Description: "metadata contains the object metadata", Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, - "items": { + "spec": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Flavor.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Flavor"), - }, - }, - }, + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkStatus"), }, }, }, - Required: []string{"items"}, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Flavor", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FlavorResourceSpec contains the desired state of a flavor", + Description: "NetworkFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Description: "name of the existing resource", Type: []string{"string"}, Format: "", }, }, "description": { SchemaProps: spec.SchemaProps{ - Description: "description contains a free form description of the flavor.", + Description: "description of the existing resource", Type: []string{"string"}, Format: "", }, }, - "ram": { + "external": { SchemaProps: spec.SchemaProps{ - Description: "ram is the memory of the flavor, measured in MB.", - Type: []string{"integer"}, - Format: "int32", + Description: "external indicates whether the network has an external routing facility that’s not managed by the networking service.", + Type: []string{"boolean"}, + Format: "", }, }, - "vcpus": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "vcpus is the number of vcpus for the flavor.", - Type: []string{"integer"}, - Format: "int32", + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Type: []string{"string"}, + Format: "", }, }, - "disk": { + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "disk is the size of the root disk that will be created in GiB. If 0 the root disk will be set to exactly the size of the image used to deploy the instance. However, in this case the scheduler cannot select the compute host based on the virtual image size. Therefore, 0 should only be used for volume booted instances or for testing purposes. Volume-backed instances can be enforced for flavors with zero root disk via the os_compute_api:servers:create:zero_disk_flavor policy rule.", - Default: 0, - Type: []string{"integer"}, - Format: "int32", + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "swap": { + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "swap is the size of a dedicated swap disk that will be allocated, in MiB. If 0 (the default), no dedicated swap disk will be created.", - Type: []string{"integer"}, - Format: "int32", + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "isPublic": { + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "isPublic flags a flavor as being available to all projects or not.", - Type: []string{"boolean"}, - Format: "", + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "ephemeral": { + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "ephemeral is the size of the ephemeral disk that will be created, in GiB. Ephemeral disks may be written over on server state changes. So should only be used as a scratch space for applications that are aware of its limitations. Defaults to 0.", - Type: []string{"integer"}, - Format: "int32", + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, }, - Required: []string{"ram", "vcpus", "disk"}, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FlavorResourceStatus represents the observed state of the resource.", + Description: "NetworkImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the flavor. Might not be unique.", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, - "ram": { - SchemaProps: spec.SchemaProps{ - Description: "ram is the memory of the flavor, measured in MB.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "vcpus": { - SchemaProps: spec.SchemaProps{ - Description: "vcpus is the number of vcpus for the flavor.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "disk": { - SchemaProps: spec.SchemaProps{ - Description: "disk is the size of the root disk that will be created in GiB.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "swap": { - SchemaProps: spec.SchemaProps{ - Description: "swap is the size of a dedicated swap disk that will be allocated, in MiB.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "isPublic": { - SchemaProps: spec.SchemaProps{ - Description: "isPublic flags a flavor as being available to all projects or not.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "ephemeral": { + "filter": { SchemaProps: spec.SchemaProps{ - Description: "ephemeral is the size of the ephemeral disk, in GiB.", - Type: []string{"integer"}, - Format: "int32", + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkFilter"), }, }, }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FlavorSpec defines the desired state of an ORC object.", + Description: "NetworkList contains a list of Network.", Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "import": { - SchemaProps: spec.SchemaProps{ - Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorImport"), - }, - }, - "resource": { + Properties: map[string]spec.Schema{ + "kind": { SchemaProps: spec.SchemaProps{ - Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceSpec"), + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", }, }, - "managementPolicy": { + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, - "managedOptions": { + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "managedOptions specifies options which may be applied to managed objects.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, }, - "cloudCredentialsRef": { + "items": { SchemaProps: spec.SchemaProps{ - Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + Description: "items contains a list of Network.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Network"), + }, + }, + }, }, }, }, - Required: []string{"cloudCredentialsRef"}, + Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Network", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FlavorStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FlavorStatus defines the observed state of an ORC resource.", + Description: "NetworkResourceSpec contains the desired state of a network", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "conditions": { + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge", + "x-kubernetes-list-type": "set", }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Description: "tags is a list of tags which will be applied to the network.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + Default: "", + Type: []string{"string"}, + Format: "", }, }, }, }, }, - "id": { + "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", + Description: "adminStateUp is the administrative state of the network, which is up (true) or down (false)", + Type: []string{"boolean"}, + Format: "", + }, + }, + "dnsDomain": { + SchemaProps: spec.SchemaProps{ + Description: "dnsDomain is the DNS domain of the network", Type: []string{"string"}, Format: "", }, }, - "resource": { + "mtu": { SchemaProps: spec.SchemaProps{ - Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceStatus"), + Description: "mtu is the the maximum transmission unit value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6. Defaults to 1500.", + Type: []string{"integer"}, + Format: "int32", }, }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FlavorResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIP(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "FloatingIP is the Schema for an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { + "portSecurityEnabled": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, + Description: "portSecurityEnabled is the port security status of the network. Valid values are enabled (true) and disabled (false). This value is used as the default value of port_security_enabled field of a newly created port.", + Type: []string{"boolean"}, Format: "", }, }, - "apiVersion": { + "external": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, + Description: "external indicates whether the network has an external routing facility that’s not managed by the networking service.", + Type: []string{"boolean"}, Format: "", }, }, - "metadata": { + "shared": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + Description: "shared indicates whether this resource is shared across all projects. By default, only administrative users can change this value.", + Type: []string{"boolean"}, + Format: "", }, }, - "spec": { + "availabilityZoneHints": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPSpec"), + Description: "availabilityZoneHints is the availability zone candidate for the network.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "status": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPStatus"), + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Type: []string{"string"}, + Format: "", }, }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FloatingIPFilter specifies a query to select an OpenStack floatingip. At least one property must be set.", + Description: "NetworkResourceStatus represents the observed state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "floatingIP": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "floatingIP is the floatingip address.", + Description: "name is a Human-readable name for the network. Might not be unique.", Type: []string{"string"}, Format: "", }, }, "description": { SchemaProps: spec.SchemaProps{ - Description: "description of the existing resource", - Type: []string{"string"}, - Format: "", - }, - }, - "floatingNetworkRef": { - SchemaProps: spec.SchemaProps{ - Description: "floatingNetworkRef is a reference to the ORC Network which this resource is associated with.", - Type: []string{"string"}, - Format: "", - }, - }, - "portRef": { - SchemaProps: spec.SchemaProps{ - Description: "portRef is a reference to the ORC Port which this resource is associated with.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "projectRef": { + "projectID": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "projectID is the project owner of the network.", Type: []string{"string"}, Format: "", }, }, "status": { SchemaProps: spec.SchemaProps{ - Description: "status is the status of the floatingip.", + Description: "status indicates whether network is currently operational. Possible values include `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.", Type: []string{"string"}, Format: "", }, @@ -1851,11 +5772,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref c "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Description: "tags is the list of tags on the resource.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -1868,14 +5789,40 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref c }, }, }, - "tagsAny": { + "createdAt": { + SchemaProps: spec.SchemaProps{ + Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "updatedAt": { + SchemaProps: spec.SchemaProps{ + Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "revisionNumber": { + SchemaProps: spec.SchemaProps{ + Description: "revisionNumber optionally set via extensions/standard-attr-revisions", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "adminStateUp": { + SchemaProps: spec.SchemaProps{ + Description: "adminStateUp is the administrative state of the network, which is up (true) or down (false).", + Type: []string{"boolean"}, + Format: "", + }, + }, + "availabilityZoneHints": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Description: "availabilityZoneHints is the availability zone candidate for the network.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -1888,34 +5835,55 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref c }, }, }, - "notTags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "dnsDomain": { + SchemaProps: spec.SchemaProps{ + Description: "dnsDomain is the DNS domain of the network", + Type: []string{"string"}, + Format: "", + }, + }, + "mtu": { + SchemaProps: spec.SchemaProps{ + Description: "mtu is the the maximum transmission unit value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "portSecurityEnabled": { + SchemaProps: spec.SchemaProps{ + Description: "portSecurityEnabled is the port security status of the network. Valid values are enabled (true) and disabled (false). This value is used as the default value of port_security_enabled field of a newly created port.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "provider": { + SchemaProps: spec.SchemaProps{ + Description: "provider contains provider-network properties.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus"), + }, + }, + "external": { + SchemaProps: spec.SchemaProps{ + Description: "external defines whether the network may be used for creation of floating IPs. Only networks with this flag may be an external gateway for routers. The network must have an external routing facility that is not managed by the networking service. If the network is updated from external to internal the unused floating IPs of this network are automatically deleted when extension floatingip-autodelete-internal is present.", + Type: []string{"boolean"}, + Format: "", }, + }, + "shared": { SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "shared specifies whether the network resource can be accessed by any tenant.", + Type: []string{"boolean"}, + Format: "", }, }, - "notTagsAny": { + "subnets": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Description: "subnets associated with this network.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -1931,247 +5899,305 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPFilter(ref c }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FloatingIPImport specifies an existing resource which will be imported instead of creating a new one", + Description: "NetworkSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { + "import": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", Type: []string{"string"}, Format: "", }, }, - "filter": { + "managedOptions": { SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPFilter"), + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), }, }, }, + Required: []string{"cloudCredentialsRef"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FloatingIPList contains a list of FloatingIP.", + Description: "NetworkStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "kind": { + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, }, }, - "apiVersion": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "id is the unique identifier of the OpenStack resource.", Type: []string{"string"}, Format: "", }, }, - "metadata": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceStatus"), }, }, - "items": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of FloatingIP.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIP"), - }, - }, - }, + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, - Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIP", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_NeutronStatusMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FloatingIPResourceSpec contains the desired state of a floating IP", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "description": { + "createdAt": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", - Type: []string{"string"}, - Format: "", + Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, + "updatedAt": { SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the floatingip.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "floatingNetworkRef": { + "revisionNumber": { SchemaProps: spec.SchemaProps{ - Description: "floatingNetworkRef references the network to which the floatingip is associated.", - Type: []string{"string"}, - Format: "", + Description: "revisionNumber optionally set via extensions/standard-attr-revisions", + Type: []string{"integer"}, + Format: "int64", }, }, - "floatingSubnetRef": { + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_Port(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Port is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { SchemaProps: spec.SchemaProps{ - Description: "floatingSubnetRef references the subnet to which the floatingip is associated.", + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", Type: []string{"string"}, Format: "", }, }, - "floatingIP": { + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "floatingIP is the IP that will be assigned to the floatingip. If not set, it will be assigned automatically.", + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, - "portRef": { + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "portRef is a reference to the ORC Port which this resource is associated with.", - Type: []string{"string"}, - Format: "", + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, - "fixedIP": { + "spec": { SchemaProps: spec.SchemaProps{ - Description: "fixedIP is the IP address of the port to which the floatingip is associated.", - Type: []string{"string"}, - Format: "", + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortSpec"), }, }, - "projectRef": { + "status": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", - Type: []string{"string"}, - Format: "", + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortStatus"), }, }, }, + Required: []string{"spec"}, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "PortFilter specifies a filter to select a port. At least one parameter must be specified.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "description": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "name of the existing resource", Type: []string{"string"}, Format: "", }, }, - "floatingNetworkID": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "floatingNetworkID is the ID of the network to which the floatingip is associated.", + Description: "description of the existing resource", Type: []string{"string"}, Format: "", }, }, - "floatingIP": { + "networkRef": { SchemaProps: spec.SchemaProps{ - Description: "floatingIP is the IP address of the floatingip.", + Description: "networkRef is a reference to the ORC Network which this port is associated with.", + Default: "", Type: []string{"string"}, Format: "", }, }, - "portID": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "portID is the ID of the port to which the floatingip is associated.", + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", Type: []string{"string"}, Format: "", }, }, - "fixedIP": { + "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "fixedIP is the IP address of the port to which the floatingip is associated.", - Type: []string{"string"}, + Description: "adminStateUp is the administrative state of the port, which is up (true) or down (false).", + Type: []string{"boolean"}, Format: "", }, }, - "tenantID": { + "macAddress": { SchemaProps: spec.SchemaProps{ - Description: "tenantID is the project owner of the resource.", + Description: "macAddress is the MAC address of the port.", Type: []string{"string"}, Format: "", }, }, - "projectID": { + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "projectID is the project owner of the resource.", - Type: []string{"string"}, - Format: "", + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "status": { - SchemaProps: spec.SchemaProps{ - Description: "status indicates the current status of the resource.", - Type: []string{"string"}, - Format: "", + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, }, - }, - "routerID": { SchemaProps: spec.SchemaProps{ - Description: "routerID is the ID of the router to which the floatingip is associated.", - Type: []string{"string"}, - Format: "", + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "tags": { + "notTags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", + "x-kubernetes-list-type": "set", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is the list of tags on the resource.", + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -2184,299 +6210,368 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPResourceStat }, }, }, - "createdAt": { + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "updatedAt": { + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_PortImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PortImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { SchemaProps: spec.SchemaProps{ - Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", }, }, - "revisionNumber": { + "filter": { SchemaProps: spec.SchemaProps{ - Description: "revisionNumber optionally set via extensions/standard-attr-revisions", - Type: []string{"integer"}, - Format: "int64", + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortFilter"), }, }, }, }, }, Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FloatingIPSpec defines the desired state of an ORC object.", + Description: "PortList contains a list of Port.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "import": { - SchemaProps: spec.SchemaProps{ - Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPImport"), - }, - }, - "resource": { + "kind": { SchemaProps: spec.SchemaProps{ - Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceSpec"), + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", }, }, - "managementPolicy": { + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, - "managedOptions": { + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "managedOptions specifies options which may be applied to managed objects.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, }, - "cloudCredentialsRef": { + "items": { SchemaProps: spec.SchemaProps{ - Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + Description: "items contains a list of Port.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Port"), + }, + }, + }, }, }, }, - Required: []string{"cloudCredentialsRef"}, + Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Port", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_FloatingIPStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "FloatingIPStatus defines the observed state of an ORC resource.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "conditions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge", - }, + "min": { + SchemaProps: spec.SchemaProps{ + Description: "min is the minimum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type", + Default: 0, + Type: []string{"integer"}, + Format: "int32", }, + }, + "max": { SchemaProps: spec.SchemaProps{ - Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), - }, - }, - }, + Description: "max is the maximum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", }, }, - "id": { + }, + Required: []string{"min", "max"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", - Type: []string{"string"}, - Format: "", + Description: "min is the minimum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type", + Default: 0, + Type: []string{"integer"}, + Format: "int32", }, }, - "resource": { + "max": { SchemaProps: spec.SchemaProps{ - Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceStatus"), + Description: "max is the maximum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", }, }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FloatingIPResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_Group(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Group is the Schema for an ORC resource.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "kind": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Description: "name is a human-readable name of the port. If not set, the object's name will be used.", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "networkRef": { + SchemaProps: spec.SchemaProps{ + Description: "networkRef is a reference to the ORC Network which this port is associated with.", Type: []string{"string"}, Format: "", }, }, - "metadata": { + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags which will be applied to the port.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "allowedAddressPairs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "allowedAddressPairs are allowed addresses associated with this port.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPair"), + }, + }, + }, + }, + }, + "addresses": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + Description: "addresses are the IP addresses for the port.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Address"), + }, + }, + }, }, }, - "spec": { + "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupSpec"), + Description: "adminStateUp is the administrative state of the port, which is up (true) or down (false). The default value is true.", + Type: []string{"boolean"}, + Format: "", }, }, - "status": { + "securityGroupRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupStatus"), + Description: "securityGroupRefs are references to the security groups associated with this port.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_GroupFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupFilter defines an existing resource by its properties", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { + "vnicType": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", + Description: "vnicType specifies the type of vNIC which this port should be attached to. This is used to determine which mechanism driver(s) to be used to bind the port. The valid values are normal, macvtap, direct, baremetal, direct-physical, virtio-forwarder, smart-nic and remote-managed, although these values will not be validated in this API to ensure compatibility with future neutron changes or custom implementations. What type of vNIC is actually available depends on deployments. If not specified, the Neutron default value is used.", Type: []string{"string"}, Format: "", }, }, - "domainRef": { + "portSecurity": { SchemaProps: spec.SchemaProps{ - Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", + Description: "portSecurity controls port security for this port. When set to Enabled, port security is enabled. When set to Disabled, port security is disabled and SecurityGroupRefs must be empty. When set to Inherit (default), it takes the value from the network level.", Type: []string{"string"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_GroupImport(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupImport specifies an existing resource which will be imported instead of creating a new one", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "id": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", Type: []string{"string"}, Format: "", }, }, - "filter": { - SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupFilter"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupFilter"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_GroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupList contains a list of Group.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { + "macAddress": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Description: "macAddress is the MAC address of the port.", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "hostID": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", + Description: "hostID specifies the host where the port will be bound. Note that when the port is attached to a server, OpenStack may rebind the port to the server's actual compute host, which may differ from the specified hostID if no matching scheduler hint is used. In this case the port's status will reflect the actual binding host, not the value specified here.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostID"), }, }, - "metadata": { + "trustedVIF": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + Description: "trustedVIF indicates whether the VF for the port will become trusted by physical function to perform some privileged operations. Only admin users can create ports with this field.", + Type: []string{"boolean"}, + Format: "", }, }, - "items": { + "valueSpecs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "key", + }, + "x-kubernetes-list-type": "map", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Group.", + Description: "valueSpecs are extra parameters to include in the API request with OpenStack. This is an extension point for the API, so what they do and if they are supported, depends on the specific OpenStack implementation. This was meant to work similar to the property on Heat port resource. Since this depends on the underlying implementation, we can't predict its fields, and therefore, we don't know how to reconcile them in advance. Use this field wisely and be aware of the expected behavior.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Group"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortValueSpec"), }, }, }, }, }, + "propagateUplinkStatus": { + SchemaProps: spec.SchemaProps{ + Description: "propagateUplinkStatus represents the uplink status propagation of the port. The field is now immutable due to a limitation on Dalmatian (2024.2) release, we should address this later. https://github.com/k-orc/openstack-resource-controller/pull/641#discussion_r2694783787", + Type: []string{"boolean"}, + Format: "", + }, + }, }, - Required: []string{"items"}, + Required: []string{"networkRef"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Group", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Address", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPair", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostID", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortValueSpec"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "GroupResourceSpec contains the desired state of the resource.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Description: "name is the human-readable name of the resource. Might not be unique.", Type: []string{"string"}, Format: "", }, @@ -2488,460 +6583,339 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceSpec(ref Format: "", }, }, - "domainRef": { + "networkID": { SchemaProps: spec.SchemaProps{ - Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", + Description: "networkID is the ID of the attached network.", Type: []string{"string"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_GroupResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupResourceStatus represents the observed state of the resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { + "projectID": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the resource. Might not be unique.", + Description: "projectID is the project owner of the resource.", Type: []string{"string"}, Format: "", }, }, - "description": { + "status": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "status indicates the current status of the resource.", Type: []string{"string"}, Format: "", }, }, - "domainID": { - SchemaProps: spec.SchemaProps{ - Description: "domainID is the ID of the Domain to which the resource is associated.", - Type: []string{"string"}, - Format: "", + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, }, - }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_GroupSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupSpec defines the desired state of an ORC object.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "import": { SchemaProps: spec.SchemaProps{ - Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupImport"), + Description: "tags is the list of tags on the resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "resource": { + "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceSpec"), + Description: "adminStateUp is the administrative state of the port, which is up (true) or down (false).", + Type: []string{"boolean"}, + Format: "", }, }, - "managementPolicy": { + "macAddress": { SchemaProps: spec.SchemaProps{ - Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Description: "macAddress is the MAC address of the port.", Type: []string{"string"}, Format: "", }, }, - "managedOptions": { - SchemaProps: spec.SchemaProps{ - Description: "managedOptions specifies options which may be applied to managed objects.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), - }, - }, - "cloudCredentialsRef": { + "deviceID": { SchemaProps: spec.SchemaProps{ - Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + Description: "deviceID is the ID of the device that uses this port.", + Type: []string{"string"}, + Format: "", }, }, - }, - Required: []string{"cloudCredentialsRef"}, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_GroupStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "GroupStatus defines the observed state of an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { + "deviceOwner": { + SchemaProps: spec.SchemaProps{ + Description: "deviceOwner is the entity type that uses this port.", + Type: []string{"string"}, + Format: "", + }, + }, + "allowedAddressPairs": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Description: "allowedAddressPairs is a set of zero or more allowed address pair objects each where address pair object contains an IP address and MAC address.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPairStatus"), }, }, }, }, }, - "id": { - SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", - Type: []string{"string"}, - Format: "", - }, - }, - "resource": { - SchemaProps: spec.SchemaProps{ - Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceStatus"), + "fixedIPs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.GroupResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_HostRoute(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "destination": { SchemaProps: spec.SchemaProps{ - Description: "destination for the additional route.", - Type: []string{"string"}, - Format: "", + Description: "fixedIPs is a set of zero or more fixed IP objects each where fixed IP object contains an IP address and subnet ID from which the IP address is assigned.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FixedIPStatus"), + }, + }, + }, }, }, - "nextHop": { - SchemaProps: spec.SchemaProps{ - Description: "nextHop for the additional route.", - Type: []string{"string"}, - Format: "", + "securityGroups": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, }, - }, - }, - Required: []string{"destination", "nextHop"}, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_HostRouteStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "destination": { SchemaProps: spec.SchemaProps{ - Description: "destination for the additional route.", - Type: []string{"string"}, - Format: "", + Description: "securityGroups contains the IDs of security groups applied to the port.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "nextHop": { + "propagateUplinkStatus": { SchemaProps: spec.SchemaProps{ - Description: "nextHop for the additional route.", - Type: []string{"string"}, + Description: "propagateUplinkStatus represents the uplink status propagation of the port.", + Type: []string{"boolean"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_IPv6Options(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "addressMode": { + "vnicType": { SchemaProps: spec.SchemaProps{ - Description: "addressMode specifies mechanisms for assigning IPv6 IP addresses.", + Description: "vnicType is the type of vNIC which this port is attached to.", Type: []string{"string"}, Format: "", }, }, - "raMode": { + "portSecurityEnabled": { SchemaProps: spec.SchemaProps{ - Description: "raMode specifies the IPv6 router advertisement mode. It specifies whether the networking service should transmit ICMPv6 packets.", - Type: []string{"string"}, + Description: "portSecurityEnabled indicates whether port security is enabled or not.", + Type: []string{"boolean"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_Image(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Image is the Schema for an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { + "hostID": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Description: "hostID is the ID of host where the port resides.", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "trustedVIF": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, + Description: "trustedVIF indicates whether the VF for the port will become trusted by physical function to perform some privileged operations.", + Type: []string{"boolean"}, Format: "", }, }, - "metadata": { + "createdAt": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "spec": { + "updatedAt": { SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageSpec"), + Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "status": { + "revisionNumber": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatus"), + Description: "revisionNumber optionally set via extensions/standard-attr-revisions", + Type: []string{"integer"}, + Format: "int64", }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPairStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FixedIPStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageContent(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "PortSpec defines the desired state of an ORC object.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "containerFormat": { + "import": { SchemaProps: spec.SchemaProps{ - Description: "containerFormat is the format of the image container. qcow2 and raw images do not usually have a container. This is specified as \"bare\", which is also the default. Permitted values are ami, ari, aki, bare, compressed, ovf, ova, and docker.", - Type: []string{"string"}, - Format: "", + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortImport"), }, }, - "diskFormat": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "diskFormat is the format of the disk image. Normal values are \"qcow2\", or \"raw\". Glance may be configured to support others.", - Type: []string{"string"}, - Format: "", + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceSpec"), }, }, - "download": { + "managementPolicy": { SchemaProps: spec.SchemaProps{ - Description: "download describes how to obtain image data by downloading it from a URL. Must be set when creating a managed image.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContentSourceDownload"), + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", }, }, - }, - Required: []string{"diskFormat", "download"}, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContentSourceDownload"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageContentSourceDownload(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "url": { + "managedOptions": { SchemaProps: spec.SchemaProps{ - Description: "url containing image data", - Default: "", - Type: []string{"string"}, - Format: "", + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, - "decompress": { + "resyncPeriod": { SchemaProps: spec.SchemaProps{ - Description: "decompress specifies that the source data must be decompressed with the given compression algorithm before being stored. Specifying Decompress will disable the use of Glance's web-download, as web-download cannot currently deterministically decompress downloaded content.", - Type: []string{"string"}, - Format: "", + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, - "hash": { + "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ - Description: "hash is a hash which will be used to verify downloaded data, i.e. before any decompression. If not specified, no hash verification will be performed. Specifying a Hash will disable the use of Glance's web-download, as web-download cannot currently deterministically verify the hash of downloaded content.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"), + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), }, }, }, - Required: []string{"url"}, + Required: []string{"cloudCredentialsRef"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageFilter defines a Glance query", + Description: "PortStatus defines the observed state of an ORC resource.", Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name specifies the name of a Glance image", - Type: []string{"string"}, - Format: "", - }, - }, - "visibility": { - SchemaProps: spec.SchemaProps{ - Description: "visibility specifies the visibility of a Glance image.", - Type: []string{"string"}, - Format: "", - }, - }, - "tags": { + Properties: map[string]spec.Schema{ + "conditions": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is the list of tags on the resource.", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), }, }, }, }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageHash(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "algorithm": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "algorithm is the hash algorithm used to generate value.", + Description: "id is the unique identifier of the OpenStack resource.", Type: []string{"string"}, Format: "", }, }, - "value": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "value is the hash of the image data using Algorithm. It must be hex encoded using lowercase letters.", - Type: []string{"string"}, - Format: "", + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, - Required: []string{"algorithm", "value"}, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_PortValueSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageImport specifies an existing resource which will be imported instead of creating a new one", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { + "key": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "key is the name of the Neutron API extension parameter.", Type: []string{"string"}, Format: "", }, }, - "filter": { + "value": { SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageFilter"), + Description: "value is the value of the Neutron API extension parameter.", + Type: []string{"string"}, + Format: "", }, }, }, + Required: []string{"key", "value"}, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_Project(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageList contains a list of Image.", + Description: "Project is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -2960,220 +6934,251 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageList(ref common.R }, "metadata": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", + Description: "metadata contains the object metadata", Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, - "items": { + "spec": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Image.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Image"), - }, - }, - }, + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus"), }, }, }, - Required: []string{"items"}, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Image", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageProperties(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "ProjectFilter defines an existing resource by its properties", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "architecture": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "architecture is the CPU architecture that must be supported by the hypervisor.", + Description: "name of the existing resource", Type: []string{"string"}, Format: "", }, }, - "hypervisorType": { + "domainRef": { SchemaProps: spec.SchemaProps{ - Description: "hypervisorType is the hypervisor type", + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, - "minDiskGB": { + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "minDiskGB is the minimum amount of disk space in GB that is required to boot the image", - Type: []string{"integer"}, - Format: "int32", + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "minMemoryMB": { + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "minMemoryMB is the minimum amount of RAM in MB that is required to boot the image.", - Type: []string{"integer"}, - Format: "int32", + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "hardware": { + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "hardware is a set of properties which control the virtual hardware created by Nova.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesHardware"), + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "operatingSystem": { + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "operatingSystem is a set of properties that specify and influence the behavior of the operating system within the virtual machine.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesOperatingSystem"), + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesHardware", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImagePropertiesOperatingSystem"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesHardware(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "ProjectImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "cpuSockets": { - SchemaProps: spec.SchemaProps{ - Description: "cpuSockets is the preferred number of sockets to expose to the guest", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "cpuCores": { - SchemaProps: spec.SchemaProps{ - Description: "cpuCores is the preferred number of cores to expose to the guest", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "cpuThreads": { - SchemaProps: spec.SchemaProps{ - Description: "cpuThreads is the preferred number of threads to expose to the guest", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "cpuPolicy": { - SchemaProps: spec.SchemaProps{ - Description: "cpuPolicy is used to pin the virtual CPUs (vCPUs) of instances to the host's physical CPU cores (pCPUs). Host aggregates should be used to separate these pinned instances from unpinned instances as the latter will not respect the resourcing requirements of the former.\n\nPermitted values are shared (the default), and dedicated.\n\nshared: The guest vCPUs will be allowed to freely float across host pCPUs, albeit potentially constrained by NUMA policy.\n\ndedicated: The guest vCPUs will be strictly pinned to a set of host pCPUs. In the absence of an explicit vCPU topology request, the drivers typically expose all vCPUs as sockets with one core and one thread. When strict CPU pinning is in effect the guest CPU topology will be setup to match the topology of the CPUs to which it is pinned. This option implies an overcommit ratio of 1.0. For example, if a two vCPU guest is pinned to a single host core with two threads, then the guest will get a topology of one socket, one core, two threads.", - Type: []string{"string"}, - Format: "", - }, - }, - "cpuThreadPolicy": { - SchemaProps: spec.SchemaProps{ - Description: "cpuThreadPolicy further refines a CPUPolicy of 'dedicated' by stating how hardware CPU threads in a simultaneous multithreading-based (SMT) architecture be used. SMT-based architectures include Intel processors with Hyper-Threading technology. In these architectures, processor cores share a number of components with one or more other cores. Cores in such architectures are commonly referred to as hardware threads, while the cores that a given core share components with are known as thread siblings.\n\nPermitted values are prefer (the default), isolate, and require.\n\nprefer: The host may or may not have an SMT architecture. Where an SMT architecture is present, thread siblings are preferred.\n\nisolate: The host must not have an SMT architecture or must emulate a non-SMT architecture. If the host does not have an SMT architecture, each vCPU is placed on a different core as expected. If the host does have an SMT architecture - that is, one or more cores have thread siblings - then each vCPU is placed on a different physical core. No vCPUs from other guests are placed on the same core. All but one thread sibling on each utilized core is therefore guaranteed to be unusable.\n\nrequire: The host must have an SMT architecture. Each vCPU is allocated on thread siblings. If the host does not have an SMT architecture, then it is not used. If the host has an SMT architecture, but not enough cores with free thread siblings are available, then scheduling fails.", - Type: []string{"string"}, - Format: "", - }, - }, - "cdromBus": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "cdromBus specifies the type of disk controller to attach CD-ROM devices to.", + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, - "diskBus": { + "filter": { SchemaProps: spec.SchemaProps{ - Description: "diskBus specifies the type of disk controller to attach disk devices to.", - Type: []string{"string"}, - Format: "", + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectFilter"), }, }, - "scsiModel": { + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ProjectList contains a list of Project.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { SchemaProps: spec.SchemaProps{ - Description: "scsiModel enables the use of VirtIO SCSI (virtio-scsi) to provide block device access for compute instances; by default, instances use VirtIO Block (virtio-blk). VirtIO SCSI is a para-virtualized SCSI controller device that provides improved scalability and performance, and supports advanced SCSI hardware.\n\nThe only permitted value is virtio-scsi.", + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", Type: []string{"string"}, Format: "", }, }, - "vifModel": { + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "vifModel specifies the model of virtual network interface device to use.\n\nPermitted values are e1000, e1000e, ne2k_pci, pcnet, rtl8139, virtio, and vmxnet3.", + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, - "rngModel": { + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "rngModel adds a random-number generator device to the image’s instances. This image property by itself does not guarantee that a hardware RNG will be used; it expresses a preference that may or may not be satisfied depending upon Nova configuration.", - Type: []string{"string"}, - Format: "", + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, }, - "qemuGuestAgent": { + "items": { SchemaProps: spec.SchemaProps{ - Description: "qemuGuestAgent enables QEMU guest agent.", - Type: []string{"boolean"}, - Format: "", + Description: "items contains a list of Project.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Project"), + }, + }, + }, }, }, }, + Required: []string{"items"}, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Project", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImagePropertiesOperatingSystem(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "ProjectResourceSpec contains the desired state of a project", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "distro": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "distro is the common name of the operating system distribution in lowercase.", + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", Type: []string{"string"}, Format: "", }, }, - "version": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "version is the operating system version as specified by the distributor.", + Description: "description contains a free form description of the project.", Type: []string{"string"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ImageResourceSpec contains the desired state of a Glance image", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { + "domainRef": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created Glance image. If not specified, the name of the Image object will be used.", + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, - "protected": { + "enabled": { SchemaProps: spec.SchemaProps{ - Description: "protected specifies that the image is protected from deletion. If not specified, the default is false.", + Description: "enabled defines whether a project is enabled or not. Default is true.", Type: []string{"boolean"}, Format: "", }, @@ -3185,7 +7190,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceSpec(ref }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the image. A tag has a maximum length of 255 characters.", + Description: "tags is list of simple strings assigned to a project. Tags can be used to classify projects into groups.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3198,86 +7203,45 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceSpec(ref }, }, }, - "visibility": { - SchemaProps: spec.SchemaProps{ - Description: "visibility of the image", - Type: []string{"string"}, - Format: "", - }, - }, - "properties": { - SchemaProps: spec.SchemaProps{ - Description: "properties is metadata available to consumers of the image", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageProperties"), - }, - }, - "content": { - SchemaProps: spec.SchemaProps{ - Description: "content specifies how to obtain the image content.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContent"), - }, - }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageContent", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageProperties"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageResourceStatus represents the observed state of a Glance image", + Description: "ProjectResourceStatus represents the observed state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the image. Might not be unique.", + Description: "name is a Human-readable name for the project. Might not be unique.", Type: []string{"string"}, Format: "", }, }, - "status": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "status is the image status as reported by Glance", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "protected": { - SchemaProps: spec.SchemaProps{ - Description: "protected specifies that the image is protected from deletion.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "visibility": { + "domainID": { SchemaProps: spec.SchemaProps{ - Description: "visibility of the image", + Description: "domainID is the ID of the Domain to which the resource is associated.", Type: []string{"string"}, Format: "", }, }, - "hash": { - SchemaProps: spec.SchemaProps{ - Description: "hash is the hash of the image data published by Glance. Note that this is a hash of the data stored internally by Glance, which will have been decompressed and potentially format converted depending on server-side configuration which is not visible to clients. It is expected that this hash will usually differ from the download hash.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"), - }, - }, - "sizeB": { - SchemaProps: spec.SchemaProps{ - Description: "sizeB is the size of the image data, in bytes", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "virtualSizeB": { + "enabled": { SchemaProps: spec.SchemaProps{ - Description: "virtualSizeB is the size of the disk the image data represents, in bytes", - Type: []string{"integer"}, - Format: "int64", + Description: "enabled represents whether a project is enabled or not.", + Type: []string{"boolean"}, + Format: "", }, }, "tags": { @@ -3303,28 +7267,26 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageResourceStatus(re }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageHash"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageSpec defines the desired state of an ORC object.", + Description: "ProjectSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceSpec"), }, }, "managementPolicy": { @@ -3340,6 +7302,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageSpec(ref common.R Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -3352,15 +7320,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageSpec(ref common.R }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ImageStatus defines the observed state of an ORC resource.", + Description: "ProjectStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -3397,33 +7365,46 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatus(ref common "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceStatus"), }, }, - "downloadAttempts": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "downloadAttempts is the number of times the controller has attempted to download the image contents", - Type: []string{"integer"}, - Format: "int32", + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ImageResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatusExtra(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "downloadAttempts": { + "networkType": { SchemaProps: spec.SchemaProps{ - Description: "downloadAttempts is the number of times the controller has attempted to download the image contents", + Description: "networkType is the type of physical network that this network should be mapped to. Supported values are flat, vlan, vxlan, and gre. Valid values depend on the networking back-end.", + Type: []string{"string"}, + Format: "", + }, + }, + "physicalNetwork": { + SchemaProps: spec.SchemaProps{ + Description: "physicalNetwork is the physical network where this network should be implemented. The Networking API v2.0 does not provide a way to list available physical networks. For example, the Open vSwitch plug-in configuration file defines a symbolic name that maps to specific bridges on each compute host.", + Type: []string{"string"}, + Format: "", + }, + }, + "segmentationID": { + SchemaProps: spec.SchemaProps{ + Description: "segmentationID is the ID of the isolated segment on the physical network. The network_type attribute defines the segmentation model. For example, if the network_type value is vlan, this ID is a vlan identifier. If the network_type value is gre, this ID is a gre key.", Type: []string{"integer"}, Format: "int32", }, @@ -3434,11 +7415,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ImageStatusExtra(ref c } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPair(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPair is the Schema for an ORC resource.", + Description: "Role is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -3466,34 +7447,114 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPair(ref common.Ref SchemaProps: spec.SchemaProps{ Description: "spec specifies the desired state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ Description: "status defines the observed state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleStatus"), }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignment(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPairFilter defines an existing resource by its properties", + Description: "RoleAssignment is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RoleAssignmentFilter defines import filter criteria for existing role assignments.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "roleRef": { + SchemaProps: spec.SchemaProps{ + Description: "roleRef filters by the referenced Role.", + Type: []string{"string"}, + Format: "", + }, + }, + "userRef": { + SchemaProps: spec.SchemaProps{ + Description: "userRef filters by the referenced User.", + Type: []string{"string"}, + Format: "", + }, + }, + "groupRef": { + SchemaProps: spec.SchemaProps{ + Description: "groupRef filters by the referenced Group.", + Type: []string{"string"}, + Format: "", + }, + }, + "projectRef": { + SchemaProps: spec.SchemaProps{ + Description: "projectRef filters by the referenced Project scope.", + Type: []string{"string"}, + Format: "", + }, + }, + "domainRef": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing Keypair", + Description: "domainRef filters by the referenced Domain scope.", Type: []string{"string"}, Format: "", }, @@ -3504,39 +7565,32 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairFilter(ref comm } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPairImport specifies an existing resource which will be imported instead of creating a new one", + Description: "RoleAssignmentImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { - SchemaProps: spec.SchemaProps{ - Description: "id contains the name of an existing resource. Note: This resource uses the resource name as the unique identifier, not a UUID. When specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", - Type: []string{"string"}, - Format: "", - }, - }, "filter": { SchemaProps: spec.SchemaProps{ Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairFilter"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPairList contains a list of KeyPair.", + Description: "RoleAssignmentList contains a list of RoleAssignment.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -3562,13 +7616,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairList(ref common }, "items": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of KeyPair.", + Description: "items contains a list of RoleAssignment.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPair"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignment"), }, }, }, @@ -3579,76 +7633,97 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairList(ref common }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPair", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignment", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPairResourceSpec contains the desired state of the resource.", + Description: "RoleAssignmentResourceSpec defines the desired role assignment. A role assignment grants a role to a user or group on a project or domain. Role assignments are immutable once created and identified by the combination of (role, actor, scope) rather than a separate ID.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "roleRef": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Description: "roleRef references the Role being assigned.", Type: []string{"string"}, Format: "", }, }, - "type": { + "userRef": { SchemaProps: spec.SchemaProps{ - Description: "type specifies the type of the Keypair. Allowed values are ssh or x509. If not specified, defaults to ssh.", + Description: "userRef references the User receiving the role assignment. Exactly one of userRef or groupRef must be specified.", Type: []string{"string"}, Format: "", }, }, - "publicKey": { + "groupRef": { SchemaProps: spec.SchemaProps{ - Description: "publicKey is the public key to import.", + Description: "groupRef references the Group receiving the role assignment. Exactly one of userRef or groupRef must be specified.", + Type: []string{"string"}, + Format: "", + }, + }, + "projectRef": { + SchemaProps: spec.SchemaProps{ + Description: "projectRef references the Project scope for the assignment. Exactly one of projectRef or domainRef must be specified.", + Type: []string{"string"}, + Format: "", + }, + }, + "domainRef": { + SchemaProps: spec.SchemaProps{ + Description: "domainRef references the Domain scope for the assignment. Exactly one of projectRef or domainRef must be specified.", Type: []string{"string"}, Format: "", }, }, }, - Required: []string{"publicKey"}, + Required: []string{"roleRef"}, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPairResourceStatus represents the observed state of the resource.", + Description: "RoleAssignmentResourceStatus represents the observed state of the role assignment. Note: Role assignments do not have a unique ID in OpenStack - they are identified by the combination of role, actor (user/group), and scope (project/domain).", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "roleID": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the resource. Might not be unique.", + Description: "roleID is the OpenStack ID of the assigned role.", Type: []string{"string"}, Format: "", }, }, - "fingerprint": { + "userID": { SchemaProps: spec.SchemaProps{ - Description: "fingerprint is the fingerprint of the public key", + Description: "userID is the OpenStack ID of the user (if actorType is User).", Type: []string{"string"}, Format: "", }, }, - "publicKey": { + "groupID": { SchemaProps: spec.SchemaProps{ - Description: "publicKey is the public key of the Keypair", + Description: "groupID is the OpenStack ID of the group (if actorType is Group).", Type: []string{"string"}, Format: "", }, }, - "type": { + "projectID": { SchemaProps: spec.SchemaProps{ - Description: "type is the type of the Keypair (ssh or x509)", + Description: "projectID is the OpenStack ID of the project scope (if scopeType is Project).", + Type: []string{"string"}, + Format: "", + }, + }, + "domainID": { + SchemaProps: spec.SchemaProps{ + Description: "domainID is the OpenStack ID of the domain scope (if scopeType is Domain).", Type: []string{"string"}, Format: "", }, @@ -3659,23 +7734,23 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairResourceStatus( } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPairSpec defines the desired state of an ORC object.", + Description: "RoleAssignmentSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentResourceSpec"), }, }, "managementPolicy": { @@ -3691,6 +7766,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairSpec(ref common Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -3703,15 +7784,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairSpec(ref common }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "KeyPairStatus defines the observed state of an ORC resource.", + Description: "RoleAssignmentStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -3738,101 +7819,31 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_KeyPairStatus(ref comm }, }, }, - "id": { - SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", - Type: []string{"string"}, - Format: "", - }, - }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.KeyPairResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ManagedOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "onDelete": { - SchemaProps: spec.SchemaProps{ - Description: "onDelete specifies the behaviour of the controller when the ORC object is deleted. Options are `delete` - delete the OpenStack resource; `detach` - do not delete the OpenStack resource. If not specified, the default is `delete`.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_Network(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Network is the Schema for an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentResourceStatus"), }, }, - "status": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkStatus"), + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkFilter defines an existing resource by its properties", + Description: "RoleFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -3842,118 +7853,24 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkFilter(ref comm Format: "", }, }, - "description": { - SchemaProps: spec.SchemaProps{ - Description: "description of the existing resource", - Type: []string{"string"}, - Format: "", - }, - }, - "external": { - SchemaProps: spec.SchemaProps{ - Description: "external indicates whether the network has an external routing facility that’s not managed by the networking service.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "projectRef": { + "domainRef": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "tagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "notTags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "notTagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, }, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkImport specifies an existing resource which will be imported instead of creating a new one", + Description: "RoleImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ "id": { @@ -3966,22 +7883,22 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkImport(ref comm "filter": { SchemaProps: spec.SchemaProps{ Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkFilter"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkList contains a list of Network.", + Description: "RoleList contains a list of Role.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -4007,13 +7924,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkList(ref common }, "items": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Network.", + Description: "items contains a list of Role.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Network"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role"), }, }, }, @@ -4024,15 +7941,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkList(ref common }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Network", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkResourceSpec contains the desired state of a network", + Description: "RoleResourceSpec contains the desired state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -4049,91 +7966,9 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceSpec(re Format: "", }, }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the network.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "adminStateUp": { - SchemaProps: spec.SchemaProps{ - Description: "adminStateUp is the administrative state of the network, which is up (true) or down (false)", - Type: []string{"boolean"}, - Format: "", - }, - }, - "dnsDomain": { - SchemaProps: spec.SchemaProps{ - Description: "dnsDomain is the DNS domain of the network", - Type: []string{"string"}, - Format: "", - }, - }, - "mtu": { - SchemaProps: spec.SchemaProps{ - Description: "mtu is the the maximum transmission unit value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6. Defaults to 1500.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "portSecurityEnabled": { - SchemaProps: spec.SchemaProps{ - Description: "portSecurityEnabled is the port security status of the network. Valid values are enabled (true) and disabled (false). This value is used as the default value of port_security_enabled field of a newly created port.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "external": { - SchemaProps: spec.SchemaProps{ - Description: "external indicates whether the network has an external routing facility that’s not managed by the networking service.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "shared": { - SchemaProps: spec.SchemaProps{ - Description: "shared indicates whether this resource is shared across all projects. By default, only administrative users can change this value.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "availabilityZoneHints": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "availabilityZoneHints is the availability zone candidate for the network.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "projectRef": { + "domainRef": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", Type: []string{"string"}, Format: "", }, @@ -4144,16 +7979,16 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceSpec(re } } -func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkResourceStatus represents the observed state of the resource.", + Description: "RoleResourceStatus represents the observed state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the network. Might not be unique.", + Description: "name is a Human-readable name for the resource. Might not be unique.", Type: []string{"string"}, Format: "", }, @@ -4165,172 +8000,36 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkResourceStatus( Format: "", }, }, - "projectID": { - SchemaProps: spec.SchemaProps{ - Description: "projectID is the project owner of the network.", - Type: []string{"string"}, - Format: "", - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Description: "status indicates whether network is currently operational. Possible values include `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.", - Type: []string{"string"}, - Format: "", - }, - }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tags is the list of tags on the resource.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "createdAt": { - SchemaProps: spec.SchemaProps{ - Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "updatedAt": { - SchemaProps: spec.SchemaProps{ - Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "revisionNumber": { - SchemaProps: spec.SchemaProps{ - Description: "revisionNumber optionally set via extensions/standard-attr-revisions", - Type: []string{"integer"}, - Format: "int64", - }, - }, - "adminStateUp": { - SchemaProps: spec.SchemaProps{ - Description: "adminStateUp is the administrative state of the network, which is up (true) or down (false).", - Type: []string{"boolean"}, - Format: "", - }, - }, - "availabilityZoneHints": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "availabilityZoneHints is the availability zone candidate for the network.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "dnsDomain": { + "domainID": { SchemaProps: spec.SchemaProps{ - Description: "dnsDomain is the DNS domain of the network", + Description: "domainID is the ID of the Domain to which the resource is associated.", Type: []string{"string"}, Format: "", }, }, - "mtu": { - SchemaProps: spec.SchemaProps{ - Description: "mtu is the the maximum transmission unit value to address fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "portSecurityEnabled": { - SchemaProps: spec.SchemaProps{ - Description: "portSecurityEnabled is the port security status of the network. Valid values are enabled (true) and disabled (false). This value is used as the default value of port_security_enabled field of a newly created port.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "provider": { - SchemaProps: spec.SchemaProps{ - Description: "provider contains provider-network properties.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus"), - }, - }, - "external": { - SchemaProps: spec.SchemaProps{ - Description: "external defines whether the network may be used for creation of floating IPs. Only networks with this flag may be an external gateway for routers. The network must have an external routing facility that is not managed by the networking service. If the network is updated from external to internal the unused floating IPs of this network are automatically deleted when extension floatingip-autodelete-internal is present.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "shared": { - SchemaProps: spec.SchemaProps{ - Description: "shared specifies whether the network resource can be accessed by any tenant.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "subnets": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "subnets associated with this network.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkSpec defines the desired state of an ORC object.", + Description: "RoleSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceSpec"), }, }, "managementPolicy": { @@ -4346,6 +8045,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkSpec(ref common Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -4358,15 +8063,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkSpec(ref common }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RoleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NetworkStatus defines the observed state of an ORC resource.", + Description: "RoleStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -4403,55 +8108,28 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_NetworkStatus(ref comm "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.NetworkResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_NeutronStatusMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "createdAt": { - SchemaProps: spec.SchemaProps{ - Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceStatus"), }, }, - "updatedAt": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "revisionNumber": { - SchemaProps: spec.SchemaProps{ - Description: "revisionNumber optionally set via extensions/standard-attr-revisions", - Type: []string{"integer"}, - Format: "int64", - }, - }, }, }, }, Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_Port(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_Router(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Port is the Schema for an ORC resource.", + Description: "Router is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -4479,29 +8157,30 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Port(ref common.Refere SchemaProps: spec.SchemaProps{ Description: "spec specifies the desired state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ Description: "status defines the observed state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterStatus"), }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_PortFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PortFilter specifies a filter to select a port. At least one parameter must be specified.", + Description: "RouterFilter specifies a query to select an OpenStack router. At least one property must be set.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -4518,14 +8197,6 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortFilter(ref common. Format: "", }, }, - "networkRef": { - SchemaProps: spec.SchemaProps{ - Description: "networkRef is a reference to the ORC Network which this port is associated with.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, "projectRef": { SchemaProps: spec.SchemaProps{ Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", @@ -4533,13 +8204,6 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortFilter(ref common. Format: "", }, }, - "adminStateUp": { - SchemaProps: spec.SchemaProps{ - Description: "adminStateUp is the administrative state of the port, which is up (true) or down (false).", - Type: []string{"boolean"}, - Format: "", - }, - }, "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ @@ -4587,78 +8251,273 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortFilter(ref common. }, }, SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RouterImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterface(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RouterInterface is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RouterInterfaceList contains a list of RouterInterface.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of RouterInterface.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterface"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterface", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "type specifies the type of the router interface.", + Type: []string{"string"}, + Format: "", + }, + }, + "routerRef": { + SchemaProps: spec.SchemaProps{ + Description: "routerRef references the router to which this interface belongs.", + Type: []string{"string"}, + Format: "", + }, + }, + "subnetRef": { + SchemaProps: spec.SchemaProps{ + Description: "subnetRef references the subnet the router interface is created on.", + Type: []string{"string"}, + Format: "", + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), }, }, - "notTagsAny": { + }, + Required: []string{"type", "routerRef"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", }, }, SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), }, }, }, }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_PortImport(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "PortImport specifies an existing resource which will be imported instead of creating a new one", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ "id": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "id is the unique identifier of the port created for the router interface", Type: []string{"string"}, Format: "", }, }, - "filter": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortFilter"), + Description: "lastSyncTime is the timestamp of the last successful reconciliation of the resource.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortFilter"}, + "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_PortList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PortList contains a list of Port.", + Description: "RouterList contains a list of Router.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -4684,13 +8543,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortList(ref common.Re }, "items": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Port.", + Description: "items contains a list of Router.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Port"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Router"), }, }, }, @@ -4701,68 +8560,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortList(ref common.Re }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Port", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "min": { - SchemaProps: spec.SchemaProps{ - Description: "min is the minimum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - "max": { - SchemaProps: spec.SchemaProps{ - Description: "max is the maximum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code.", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - Required: []string{"min", "max"}, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_PortRangeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "min": { - SchemaProps: spec.SchemaProps{ - Description: "min is the minimum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - "max": { - SchemaProps: spec.SchemaProps{ - Description: "max is the maximum port number in the range that is matched by the security group rule. If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code.", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - }, - }, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Router", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ @@ -4770,7 +8572,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref c Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name is a human-readable name of the port. If not set, the object's name will be used.", + Description: "name is a human-readable name of the router. If not set, the object's name will be used.", Type: []string{"string"}, Format: "", }, @@ -4782,13 +8584,6 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref c Format: "", }, }, - "networkRef": { - SchemaProps: spec.SchemaProps{ - Description: "networkRef is a reference to the ORC Network which this port is associated with.", - Type: []string{"string"}, - Format: "", - }, - }, "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ @@ -4796,7 +8591,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref c }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the port.", + Description: "tags is a list of tags which will be applied to the router.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4809,59 +8604,47 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref c }, }, }, - "allowedAddressPairs": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "allowedAddressPairs are allowed addresses associated with this port.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPair"), - }, - }, - }, + Description: "adminStateUp represents the administrative state of the resource, which is up (true) or down (false). Default is true.", + Type: []string{"boolean"}, + Format: "", }, }, - "addresses": { + "externalGateways": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "addresses are the IP addresses for the port.", + Description: "externalGateways is a list of external gateways for the router. Multiple gateways are not currently supported by ORC.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Address"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGateway"), }, }, }, }, }, - "adminStateUp": { + "distributed": { SchemaProps: spec.SchemaProps{ - Description: "adminStateUp is the administrative state of the port, which is up (true) or down (false). The default value is true.", + Description: "distributed indicates whether the router is distributed or not. It is available when dvr extension is enabled.", Type: []string{"boolean"}, Format: "", }, }, - "securityGroupRefs": { + "availabilityZoneHints": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "set", }, }, SchemaProps: spec.SchemaProps{ - Description: "securityGroupRefs are the names of the security groups associated with this port.", + Description: "availabilityZoneHints is the availability zone candidate for the router.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4874,20 +8657,6 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref c }, }, }, - "vnicType": { - SchemaProps: spec.SchemaProps{ - Description: "vnicType specifies the type of vNIC which this port should be attached to. This is used to determine which mechanism driver(s) to be used to bind the port. The valid values are normal, macvtap, direct, baremetal, direct-physical, virtio-forwarder, smart-nic and remote-managed, although these values will not be validated in this API to ensure compatibility with future neutron changes or custom implementations. What type of vNIC is actually available depends on deployments. If not specified, the Neutron default value is used.", - Type: []string{"string"}, - Format: "", - }, - }, - "portSecurity": { - SchemaProps: spec.SchemaProps{ - Description: "portSecurity controls port security for this port. When set to Enabled, port security is enabled. When set to Disabled, port security is disabled and SecurityGroupRefs must be empty. When set to Inherit (default), it takes the value from the network level.", - Type: []string{"string"}, - Format: "", - }, - }, "projectRef": { SchemaProps: spec.SchemaProps{ Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", @@ -4896,15 +8665,14 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceSpec(ref c }, }, }, - Required: []string{"networkRef"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Address", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPair"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGateway"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ @@ -4924,13 +8692,6 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceStatus(ref Format: "", }, }, - "networkID": { - SchemaProps: spec.SchemaProps{ - Description: "networkID is the ID of the attached network.", - Type: []string{"string"}, - Format: "", - }, - }, "projectID": { SchemaProps: spec.SchemaProps{ Description: "projectID is the project owner of the resource.", @@ -4967,78 +8728,38 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceStatus(ref }, "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "adminStateUp is the administrative state of the port, which is up (true) or down (false).", + Description: "adminStateUp is the administrative state of the router, which is up (true) or down (false).", Type: []string{"boolean"}, Format: "", }, }, - "macAddress": { - SchemaProps: spec.SchemaProps{ - Description: "macAddress is the MAC address of the port.", - Type: []string{"string"}, - Format: "", - }, - }, - "deviceID": { - SchemaProps: spec.SchemaProps{ - Description: "deviceID is the ID of the device that uses this port.", - Type: []string{"string"}, - Format: "", - }, - }, - "deviceOwner": { - SchemaProps: spec.SchemaProps{ - Description: "deviceOwner is the entity type that uses this port.", - Type: []string{"string"}, - Format: "", - }, - }, - "allowedAddressPairs": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "allowedAddressPairs is a set of zero or more allowed address pair objects each where address pair object contains an IP address and MAC address.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPairStatus"), - }, - }, - }, - }, - }, - "fixedIPs": { + "externalGateways": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "fixedIPs is a set of zero or more fixed IP objects each where fixed IP object contains an IP address and subnet ID from which the IP address is assigned.", + Description: "externalGateways is a list of external gateways for the router.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FixedIPStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGatewayStatus"), }, }, }, }, }, - "securityGroups": { + "availabilityZoneHints": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "securityGroups contains the IDs of security groups applied to the port.", + Description: "availabilityZoneHints is the availability zone candidate for the router.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5051,71 +8772,31 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortResourceStatus(ref }, }, }, - "propagateUplinkStatus": { - SchemaProps: spec.SchemaProps{ - Description: "propagateUplinkStatus represents the uplink status propagation of the port.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "vnicType": { - SchemaProps: spec.SchemaProps{ - Description: "vnicType is the type of vNIC which this port is attached to.", - Type: []string{"string"}, - Format: "", - }, - }, - "portSecurityEnabled": { - SchemaProps: spec.SchemaProps{ - Description: "portSecurityEnabled indicates whether port security is enabled or not.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "createdAt": { - SchemaProps: spec.SchemaProps{ - Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "updatedAt": { - SchemaProps: spec.SchemaProps{ - Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, - "revisionNumber": { - SchemaProps: spec.SchemaProps{ - Description: "revisionNumber optionally set via extensions/standard-attr-revisions", - Type: []string{"integer"}, - Format: "int64", - }, - }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllowedAddressPairStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.FixedIPStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGatewayStatus"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_PortSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PortSpec defines the desired state of an ORC object.", + Description: "RouterSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceSpec"), }, }, "managementPolicy": { @@ -5131,6 +8812,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortSpec(ref common.Re Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -5143,15 +8830,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortSpec(ref common.Re }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_PortStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_RouterStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PortStatus defines the observed state of an ORC resource.", + Description: "RouterStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -5188,22 +8875,28 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_PortStatus(ref common. "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_Project(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Project is the Schema for an ORC resource.", + Description: "SecurityGroup is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -5231,29 +8924,30 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Project(ref common.Ref SchemaProps: spec.SchemaProps{ Description: "spec specifies the desired state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ Description: "status defines the observed state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupStatus"), }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ProjectFilter defines an existing resource by its properties", + Description: "SecurityGroupFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -5263,6 +8957,20 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectFilter(ref comm Format: "", }, }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "projectRef": { + SchemaProps: spec.SchemaProps{ + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Type: []string{"string"}, + Format: "", + }, + }, "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ @@ -5349,11 +9057,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectFilter(ref comm } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ProjectImport specifies an existing resource which will be imported instead of creating a new one", + Description: "SecurityGroupImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ "id": { @@ -5366,22 +9074,22 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectImport(ref comm "filter": { SchemaProps: spec.SchemaProps{ Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectFilter"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ProjectList contains a list of Project.", + Description: "SecurityGroupList contains a list of SecurityGroup.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -5407,13 +9115,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectList(ref common }, "items": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Project.", + Description: "items contains a list of SecurityGroup.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Project"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroup"), }, }, }, @@ -5424,15 +9132,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectList(ref common }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Project", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroup", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ProjectResourceSpec contains the desired state of a project", + Description: "SecurityGroupResourceSpec contains the desired state of a security group", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -5444,18 +9152,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceSpec(re }, "description": { SchemaProps: spec.SchemaProps{ - Description: "description contains a free form description of the project.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "enabled": { - SchemaProps: spec.SchemaProps{ - Description: "enabled defines whether a project is enabled or not. Default is true.", - Type: []string{"boolean"}, - Format: "", - }, - }, "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ @@ -5463,7 +9164,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceSpec(re }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is list of simple strings assigned to a project. Tags can be used to classify projects into groups.", + Description: "tags is a list of tags which will be applied to the security group.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5476,365 +9177,214 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceSpec(re }, }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ProjectResourceStatus represents the observed state of the resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the project. Might not be unique.", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { - SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", - Type: []string{"string"}, - Format: "", - }, - }, - "enabled": { + "stateful": { SchemaProps: spec.SchemaProps{ - Description: "enabled represents whether a project is enabled or not.", + Description: "stateful indicates if the security group is stateful or stateless.", Type: []string{"boolean"}, Format: "", }, }, - "tags": { + "rules": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is the list of tags on the resource.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ProjectSpec defines the desired state of an ORC object.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "import": { - SchemaProps: spec.SchemaProps{ - Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectImport"), - }, - }, - "resource": { - SchemaProps: spec.SchemaProps{ - Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceSpec"), - }, - }, - "managementPolicy": { - SchemaProps: spec.SchemaProps{ - Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", - Type: []string{"string"}, - Format: "", - }, - }, - "managedOptions": { - SchemaProps: spec.SchemaProps{ - Description: "managedOptions specifies options which may be applied to managed objects.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), - }, - }, - "cloudCredentialsRef": { - SchemaProps: spec.SchemaProps{ - Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), - }, - }, - }, - Required: []string{"cloudCredentialsRef"}, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceSpec"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ProjectStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ProjectStatus defines the observed state of an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Description: "rules is a list of security group rules belonging to this SG.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRule"), }, - }, - }, - }, - }, - "id": { - SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", - Type: []string{"string"}, - Format: "", + }, + }, }, }, - "resource": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceStatus"), + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Type: []string{"string"}, + Format: "", }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRule"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "SecurityGroupResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "networkType": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "networkType is the type of physical network that this network should be mapped to. Supported values are flat, vlan, vxlan, and gre. Valid values depend on the networking back-end.", + Description: "name is a Human-readable name for the security group. Might not be unique.", Type: []string{"string"}, Format: "", }, }, - "physicalNetwork": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "physicalNetwork is the physical network where this network should be implemented. The Networking API v2.0 does not provide a way to list available physical networks. For example, the Open vSwitch plug-in configuration file defines a symbolic name that maps to specific bridges on each compute host.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "segmentationID": { + "projectID": { SchemaProps: spec.SchemaProps{ - Description: "segmentationID is the ID of the isolated segment on the physical network. The network_type attribute defines the segmentation model. For example, if the network_type value is vlan, this ID is a vlan identifier. If the network_type value is gre, this ID is a gre key.", - Type: []string{"integer"}, - Format: "int32", + Description: "projectID is the project owner of the security group.", + Type: []string{"string"}, + Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Role is the Schema for an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", + Description: "tags is the list of tags on the resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "apiVersion": { + "stateful": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, + Description: "stateful indicates if the security group is stateful or stateless.", + Type: []string{"boolean"}, Format: "", }, }, - "metadata": { + "rules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + Description: "rules is a list of security group rules belonging to this SG.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRuleStatus"), + }, + }, + }, }, }, - "spec": { + "createdAt": { SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleSpec"), + Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "status": { + "updatedAt": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleStatus"), + Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "revisionNumber": { + SchemaProps: spec.SchemaProps{ + Description: "revisionNumber optionally set via extensions/standard-attr-revisions", + Type: []string{"integer"}, + Format: "int64", }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRuleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RoleFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRule(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RoleFilter defines an existing resource by its properties", + Description: "SecurityGroupRule defines a Security Group rule", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "domainRef": { + "direction": { SchemaProps: spec.SchemaProps{ - Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", + Description: "direction represents the direction in which the security group rule is applied. Can be ingress or egress.", Type: []string{"string"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_RoleImport(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "RoleImport specifies an existing resource which will be imported instead of creating a new one", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "id": { + "remoteIPPrefix": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6)", Type: []string{"string"}, Format: "", }, }, - "filter": { - SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleFilter"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleFilter"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_RoleList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "RoleList contains a list of Role.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { + "protocol": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Description: "protocol is the IP protocol is represented by a string", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "ethertype": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "ethertype must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules.", Type: []string{"string"}, Format: "", }, }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { + "portRange": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Role.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role"), - }, - }, - }, + Description: "portRange sets the minimum and maximum ports range that the security group rule matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than or equal to the PortRange.Max attribute value. If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max should be an ICMP type", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeSpec"), }, }, }, - Required: []string{"items"}, + Required: []string{"ethertype"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeSpec"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRuleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RoleResourceSpec contains the desired state of the resource.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Description: "id is the ID of the security group rule.", Type: []string{"string"}, Format: "", }, @@ -5846,70 +9396,72 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceSpec(ref c Format: "", }, }, - "domainRef": { + "direction": { SchemaProps: spec.SchemaProps{ - Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", + Description: "direction represents the direction in which the security group rule is applied. Can be ingress or egress.", Type: []string{"string"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_RoleResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "RoleResourceStatus represents the observed state of the resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { + "remoteGroupID": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the resource. Might not be unique.", + Description: "remoteGroupID is the remote group UUID to associate with this security group rule RemoteGroupID", Type: []string{"string"}, Format: "", }, }, - "description": { + "remoteIPPrefix": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6)", Type: []string{"string"}, Format: "", }, }, - "domainID": { + "protocol": { SchemaProps: spec.SchemaProps{ - Description: "domainID is the ID of the Domain to which the resource is associated.", + Description: "protocol is the IP protocol can be represented by a string, an integer, or null", + Type: []string{"string"}, + Format: "", + }, + }, + "ethertype": { + SchemaProps: spec.SchemaProps{ + Description: "ethertype must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules.", Type: []string{"string"}, Format: "", }, }, + "portRange": { + SchemaProps: spec.SchemaProps{ + Description: "portRange sets the minimum and maximum ports range that the security group rule matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than or equal to the PortRange.Max attribute value. If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max should be an ICMP type", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeStatus"), + }, + }, }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeStatus"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RoleSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RoleSpec defines the desired state of an ORC object.", + Description: "SecurityGroupSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceSpec"), }, }, "managementPolicy": { @@ -5925,6 +9477,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RoleSpec(ref common.Re Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -5937,15 +9495,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RoleSpec(ref common.Re }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RoleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RoleStatus defines the observed state of an ORC resource.", + Description: "SecurityGroupStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -5982,22 +9540,28 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RoleStatus(ref common. "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_Router(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_Server(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Router is the Schema for an ORC resource.", + Description: "Server is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -6025,48 +9589,70 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Router(ref common.Refe SchemaProps: spec.SchemaProps{ Description: "spec specifies the desired state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ Description: "status defines the observed state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerStatus"), }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerBootVolumeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RouterFilter specifies a query to select an OpenStack router. At least one property must be set.", + Description: "ServerBootVolumeSpec defines the boot volume for boot-from-volume server creation. When specified, the server boots from this volume instead of an image.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "volumeRef": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", + Description: "volumeRef is a reference to a Volume object. The volume must be bootable (created from an image) and available before server creation.", Type: []string{"string"}, Format: "", }, }, - "description": { + "tag": { SchemaProps: spec.SchemaProps{ - Description: "description of the existing resource", + Description: "tag is the device tag applied to the volume.", Type: []string{"string"}, Format: "", }, }, - "projectRef": { + }, + Required: []string{"volumeRef"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "availabilityZone": { + SchemaProps: spec.SchemaProps{ + Description: "availabilityZone is the availability zone of the existing resource", Type: []string{"string"}, Format: "", }, @@ -6157,11 +9743,82 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RouterFilter(ref commo } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RouterImport specifies an existing resource which will be imported instead of creating a new one", + Description: "ServerGroup is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerGroupFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerGroupImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ "id": { @@ -6174,22 +9831,22 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RouterImport(ref commo "filter": { SchemaProps: spec.SchemaProps{ Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterFilter"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterface(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RouterInterface is the Schema for an ORC resource.", + Description: "ServerGroupList contains a list of ServerGroup.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -6208,123 +9865,217 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterface(ref co }, "metadata": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata.", + Description: "metadata contains the list metadata", Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, }, - "spec": { + "items": { SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceSpec"), + Description: "items contains a list of ServerGroup.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroup"), + }, + }, + }, }, }, - "status": { + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroup", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerGroupResourceSpec contains the desired state of a servergroup", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "policy": { + SchemaProps: spec.SchemaProps{ + Description: "policy is the policy to use for the server group.", + Type: []string{"string"}, + Format: "", + }, + }, + "rules": { + SchemaProps: spec.SchemaProps{ + Description: "rules is the rules to use for the server group.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRules"), + }, + }, + }, + Required: []string{"policy"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRules"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerGroupResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the servergroup. Might not be unique.", + Type: []string{"string"}, + Format: "", + }, + }, + "policy": { + SchemaProps: spec.SchemaProps{ + Description: "policy is the policy of the servergroup.", + Type: []string{"string"}, + Format: "", + }, + }, + "projectID": { + SchemaProps: spec.SchemaProps{ + Description: "projectID is the project owner of the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "userID": { + SchemaProps: spec.SchemaProps{ + Description: "userID of the server group.", + Type: []string{"string"}, + Format: "", + }, + }, + "rules": { + SchemaProps: spec.SchemaProps{ + Description: "rules is the rules of the server group.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRulesStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRulesStatus"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRules(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "maxServerPerHost": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceStatus"), + Description: "maxServerPerHost specifies how many servers can reside on a single compute host. It can be used only with the \"anti-affinity\" policy.", + Type: []string{"integer"}, + Format: "int32", }, }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterfaceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRulesStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RouterInterfaceList contains a list of RouterInterface.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata.", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { + "maxServerPerHost": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of RouterInterface.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterface"), - }, - }, - }, + Description: "maxServerPerHost specifies how many servers can reside on a single compute host. It can be used only with the \"anti-affinity\" policy.", + Type: []string{"integer"}, + Format: "int32", }, }, }, - Required: []string{"items"}, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterInterface", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "ServerGroupSpec defines the desired state of an ORC object.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "type": { + "import": { SchemaProps: spec.SchemaProps{ - Description: "type specifies the type of the router interface.", - Type: []string{"string"}, - Format: "", + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupImport"), }, }, - "routerRef": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "routerRef references the router to which this interface belongs.", - Type: []string{"string"}, - Format: "", + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceSpec"), }, }, - "subnetRef": { + "managementPolicy": { SchemaProps: spec.SchemaProps{ - Description: "subnetRef references the subnet the router interface is created on.", + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", Type: []string{"string"}, Format: "", }, }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, }, - Required: []string{"type", "routerRef"}, + Required: []string{"cloudCredentialsRef"}, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "ServerGroupStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { VendorExtensible: spec.VendorExtensible{ @@ -6352,166 +10103,75 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RouterInterfaceStatus( }, "id": { SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the port created for the router interface", + Description: "id is the unique identifier of the OpenStack resource.", Type: []string{"string"}, Format: "", }, }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, }, }, }, Dependencies: []string{ - "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RouterList contains a list of Router.", + Description: "ServerImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { + "filter": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Router.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Router"), - }, - }, - }, + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerFilter"), }, }, }, - Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Router", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceFixedIP(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is a human-readable name of the router. If not set, the object's name will be used.", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { + "ipAddress": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "ipAddress is the IP address assigned to the port.", Type: []string{"string"}, Format: "", }, }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the router.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "adminStateUp": { - SchemaProps: spec.SchemaProps{ - Description: "adminStateUp represents the administrative state of the resource, which is up (true) or down (false). Default is true.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "externalGateways": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "externalGateways is a list of external gateways for the router. Multiple gateways are not currently supported by ORC.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGateway"), - }, - }, - }, - }, - }, - "distributed": { - SchemaProps: spec.SchemaProps{ - Description: "distributed indicates whether the router is distributed or not. It is available when dvr extension is enabled.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "availabilityZoneHints": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "availabilityZoneHints is the availability zone candidate for the router.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "projectRef": { + "subnetID": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "subnetID is the ID of the subnet from which the IP address is allocated.", Type: []string{"string"}, Format: "", }, @@ -6519,305 +10179,398 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceSpec(ref }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGateway"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "portID": { SchemaProps: spec.SchemaProps{ - Description: "name is the human-readable name of the resource. Might not be unique.", + Description: "portID is the ID of a port attached to the server.", Type: []string{"string"}, Format: "", }, }, - "description": { + "netID": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "netID is the ID of the network to which the interface is attached.", Type: []string{"string"}, Format: "", }, }, - "projectID": { + "macAddr": { SchemaProps: spec.SchemaProps{ - Description: "projectID is the project owner of the resource.", + Description: "macAddr is the MAC address of the interface.", Type: []string{"string"}, Format: "", }, }, - "status": { + "portState": { SchemaProps: spec.SchemaProps{ - Description: "status indicates the current status of the resource.", + Description: "portState is the state of the port (e.g., ACTIVE, DOWN).", Type: []string{"string"}, Format: "", }, }, - "tags": { + "fixedIPs": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is the list of tags on the resource.", + Description: "fixedIPs is the list of fixed IP addresses assigned to the interface.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceFixedIP"), }, }, }, }, }, - "adminStateUp": { + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceFixedIP"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerList contains a list of Server.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { SchemaProps: spec.SchemaProps{ - Description: "adminStateUp is the administrative state of the router, which is up (true) or down (false).", - Type: []string{"boolean"}, + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, Format: "", }, }, - "externalGateways": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "externalGateways is a list of external gateways for the router.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGatewayStatus"), - }, - }, - }, + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", }, }, - "availabilityZoneHints": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, + }, + "items": { SchemaProps: spec.SchemaProps{ - Description: "availabilityZoneHints is the availability zone candidate for the router.", + Description: "items contains a list of Server.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Server"), }, }, }, }, }, }, + Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ExternalGatewayStatus"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Server", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RouterSpec defines the desired state of an ORC object.", + Description: "ServerMetadata represents a key-value pair for server metadata.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "import": { + "key": { SchemaProps: spec.SchemaProps{ - Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterImport"), + Description: "key is the metadata key.", + Type: []string{"string"}, + Format: "", }, }, - "resource": { + "value": { SchemaProps: spec.SchemaProps{ - Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceSpec"), + Description: "value is the metadata value.", + Type: []string{"string"}, + Format: "", }, }, - "managementPolicy": { + }, + Required: []string{"key", "value"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerMetadataStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerMetadataStatus represents a key-value pair for server metadata in status.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "key": { SchemaProps: spec.SchemaProps{ - Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Description: "key is the metadata key.", Type: []string{"string"}, Format: "", }, }, - "managedOptions": { + "value": { SchemaProps: spec.SchemaProps{ - Description: "managedOptions specifies options which may be applied to managed objects.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + Description: "value is the metadata value.", + Type: []string{"string"}, + Format: "", }, }, - "cloudCredentialsRef": { + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerPortSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "portRef": { SchemaProps: spec.SchemaProps{ - Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + Description: "portRef is a reference to a Port object. Server creation will wait for this port to be created and available.", + Type: []string{"string"}, + Format: "", }, }, }, - Required: []string{"cloudCredentialsRef"}, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceSpec"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_RouterStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "RouterStatus defines the observed state of an ORC resource.", + Description: "ServerResourceSpec contains the desired state of a server", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "conditions": { + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "imageRef": { + SchemaProps: spec.SchemaProps{ + Description: "imageRef references the image to use for the server instance. This field is required unless bootVolume is specified for boot-from-volume.", + Type: []string{"string"}, + Format: "", + }, + }, + "flavorRef": { + SchemaProps: spec.SchemaProps{ + Description: "flavorRef references the flavor to use for the server instance.", + Type: []string{"string"}, + Format: "", + }, + }, + "bootVolume": { + SchemaProps: spec.SchemaProps{ + Description: "bootVolume specifies a volume to boot from instead of an image. When specified, imageRef must be omitted. The volume must be bootable (created from an image using imageRef in the Volume spec).", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerBootVolumeSpec"), + }, + }, + "userData": { + SchemaProps: spec.SchemaProps{ + Description: "userData specifies data which will be made available to the server at boot time, either via the metadata service or a config drive. It is typically read by a configuration service such as cloud-init or ignition.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserDataSpec"), + }, + }, + "ports": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Description: "ports defines a list of ports which will be attached to the server.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerPortSpec"), }, }, }, }, }, - "id": { - SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", - Type: []string{"string"}, - Format: "", + "volumes": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, }, - }, - "resource": { SchemaProps: spec.SchemaProps{ - Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceStatus"), + Description: "volumes is a list of volumes attached to the server.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeSpec"), + }, + }, + }, }, }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RouterResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "SecurityGroup is the Schema for an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { + "availabilityZone": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Description: "availabilityZone is the availability zone in which to create the server.", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "keypairRef": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "keypairRef is a reference to a KeyPair object. The server will be created with this keypair for SSH access.", Type: []string{"string"}, Format: "", }, - }, - "metadata": { + }, + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags which will be applied to the server.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "metadata": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + Description: "metadata is a list of metadata key-value pairs which will be set on the server.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerMetadata"), + }, + }, + }, }, }, - "spec": { + "configDrive": { SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupSpec"), + Description: "configDrive specifies whether to attach a config drive to the server. When true, configuration data will be available via a special drive instead of the metadata service.", + Type: []string{"boolean"}, + Format: "", }, }, - "status": { + "schedulerHints": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupStatus"), + Description: "schedulerHints provides hints to the Nova scheduler for server placement.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSchedulerHints"), }, }, }, + Required: []string{"flavorRef", "ports"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerBootVolumeSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerMetadata", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerPortSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSchedulerHints", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserDataSpec"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupFilter defines an existing resource by its properties", + Description: "ServerResourceStatus represents the observed state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", + Description: "name is the human-readable name of the resource. Might not be unique.", Type: []string{"string"}, Format: "", }, }, - "description": { + "hostID": { SchemaProps: spec.SchemaProps{ - Description: "description of the existing resource", + Description: "hostID is the host where the server is located in the cloud.", Type: []string{"string"}, Format: "", }, }, - "projectRef": { + "status": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "status contains the current operational status of the server, such as IN_PROGRESS or ACTIVE.", Type: []string{"string"}, Format: "", }, }, - "tags": { + "imageID": { + SchemaProps: spec.SchemaProps{ + Description: "imageID indicates the OS image used to deploy the server.", + Type: []string{"string"}, + Format: "", + }, + }, + "availabilityZone": { + SchemaProps: spec.SchemaProps{ + Description: "availabilityZone is the availability zone where the server is located.", + Type: []string{"string"}, + Format: "", + }, + }, + "serverGroups": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Description: "serverGroups is a slice of strings containing the UUIDs of the server groups to which the server belongs. Currently this can contain at most one entry.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6830,54 +10583,52 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupFilter(re }, }, }, - "tagsAny": { + "volumes": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Description: "volumes contains the volumes attached to the server.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeStatus"), }, }, }, }, }, - "notTags": { + "interfaces": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Description: "interfaces contains the list of interfaces attached to the server.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceStatus"), }, }, }, }, }, - "notTagsAny": { + "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Description: "tags is the list of tags on the resource.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6890,417 +10641,572 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupFilter(re }, }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupImport(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupImport specifies an existing resource which will be imported instead of creating a new one", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "id": { + "metadata": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", - Type: []string{"string"}, - Format: "", + Description: "metadata is the list of metadata key-value pairs on the resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerMetadataStatus"), + }, + }, + }, }, }, - "filter": { + "configDrive": { SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupFilter"), + Description: "configDrive indicates whether the server was booted with a config drive.", + Type: []string{"boolean"}, + Format: "", }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerMetadataStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeStatus"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerSchedulerHints(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupList contains a list of SecurityGroup.", + Description: "ServerSchedulerHints provides hints to the Nova scheduler for server placement.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "kind": { + "serverGroupRef": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Description: "serverGroupRef is a reference to a ServerGroup object. The server will be scheduled on a host in the specified server group.", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "differentHostServerRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "differentHostServerRefs is a list of references to Server objects. The server will be scheduled on a different host than all specified servers.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "sameHostServerRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "sameHostServerRefs is a list of references to Server objects. The server will be scheduled on the same host as all specified servers.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "query": { + SchemaProps: spec.SchemaProps{ + Description: "query is a conditional statement that results in compute nodes able to host the server.", Type: []string{"string"}, Format: "", }, }, - "metadata": { + "targetCell": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + Description: "targetCell is a cell name where the server will be placed.", + Type: []string{"string"}, + Format: "", }, }, - "items": { + "differentCell": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "items contains a list of SecurityGroup.", + Description: "differentCell is a list of cell names where the server should not be placed.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroup"), + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "buildNearHostIP": { + SchemaProps: spec.SchemaProps{ + Description: "buildNearHostIP specifies a subnet of compute nodes to host the server. The host IP should be provided in an CIDR format like 10.10.10.10/24.", + Type: []string{"string"}, + Format: "", + }, + }, + "additionalProperties": { + SchemaProps: spec.SchemaProps{ + Description: "additionalProperties is a map of arbitrary key/value pairs that are not validated by Nova.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", }, }, }, }, }, }, - Required: []string{"items"}, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroup", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupResourceSpec contains the desired state of a security group", + Description: "ServerSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "import": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", - Type: []string{"string"}, - Format: "", + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerImport"), }, }, - "description": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", Type: []string{"string"}, Format: "", }, }, - "tags": { + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the security group.", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), }, }, }, }, }, - "stateful": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "stateful indicates if the security group is stateful or stateless.", - Type: []string{"boolean"}, + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, Format: "", }, }, - "rules": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "resource": { SchemaProps: spec.SchemaProps{ - Description: "rules is a list of security group rules belonging to this SG.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRule"), - }, - }, - }, + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceStatus"), }, }, - "projectRef": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", - Type: []string{"string"}, - Format: "", + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRule"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupResourceStatus represents the observed state of the resource.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "volumeRef": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the security group. Might not be unique.", + Description: "volumeRef is a reference to a Volume object. Server creation will wait for this volume to be created and available.", Type: []string{"string"}, Format: "", }, }, - "description": { + "device": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "device is the name of the device, such as `/dev/vdb`. Omit for auto-assignment", Type: []string{"string"}, Format: "", }, }, - "projectID": { + }, + Required: []string{"volumeRef"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { SchemaProps: spec.SchemaProps{ - Description: "projectID is the project owner of the security group.", + Description: "id is the ID of a volume attached to the server.", Type: []string{"string"}, Format: "", }, }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tags is the list of tags on the resource.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "stateful": { + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_Service(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Service is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { SchemaProps: spec.SchemaProps{ - Description: "stateful indicates if the security group is stateful or stateless.", - Type: []string{"boolean"}, + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, Format: "", }, }, - "rules": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "rules is a list of security group rules belonging to this SG.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRuleStatus"), - }, - }, - }, + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", }, }, - "createdAt": { + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, - "updatedAt": { + "spec": { SchemaProps: spec.SchemaProps{ - Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceSpec"), }, }, - "revisionNumber": { + "status": { SchemaProps: spec.SchemaProps{ - Description: "revisionNumber optionally set via extensions/standard-attr-revisions", - Type: []string{"integer"}, - Format: "int64", + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceStatus"), }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupRuleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRule(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupRule defines a Security Group rule", + Description: "ServiceFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "description": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "name of the existing resource", Type: []string{"string"}, Format: "", }, }, - "direction": { + "type": { SchemaProps: spec.SchemaProps{ - Description: "direction represents the direction in which the security group rule is applied. Can be ingress or egress.", + Description: "type of the existing resource", Type: []string{"string"}, Format: "", }, }, - "remoteIPPrefix": { + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServiceImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { SchemaProps: spec.SchemaProps{ - Description: "remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6)", + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, - "protocol": { + "filter": { SchemaProps: spec.SchemaProps{ - Description: "protocol is the IP protocol is represented by a string", + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServiceList contains a list of Service.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", Type: []string{"string"}, Format: "", }, }, - "ethertype": { + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "ethertype must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules.", + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, - "portRange": { + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "portRange sets the minimum and maximum ports range that the security group rule matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than or equal to the PortRange.Max attribute value. If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max should be an ICMP type", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeSpec"), + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of Service.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Service"), + }, + }, + }, }, }, }, - Required: []string{"ethertype"}, + Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Service", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupRuleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "ServiceResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { + "name": { SchemaProps: spec.SchemaProps{ - Description: "id is the ID of the security group rule.", + Description: "name indicates the name of service. If not specified, the name of the ORC resource will be used.", Type: []string{"string"}, Format: "", }, }, "description": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "description indicates the description of service.", Type: []string{"string"}, Format: "", }, }, - "direction": { + "type": { SchemaProps: spec.SchemaProps{ - Description: "direction represents the direction in which the security group rule is applied. Can be ingress or egress.", + Description: "type indicates which resource the service is responsible for.", Type: []string{"string"}, Format: "", }, }, - "remoteGroupID": { + "enabled": { SchemaProps: spec.SchemaProps{ - Description: "remoteGroupID is the remote group UUID to associate with this security group rule RemoteGroupID", - Type: []string{"string"}, + Description: "enabled indicates whether the service is enabled or not.", + Type: []string{"boolean"}, Format: "", }, }, - "remoteIPPrefix": { + }, + Required: []string{"type"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServiceResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { SchemaProps: spec.SchemaProps{ - Description: "remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6)", + Description: "name indicates the name of service.", Type: []string{"string"}, Format: "", }, }, - "protocol": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "protocol is the IP protocol can be represented by a string, an integer, or null", + Description: "description indicates the description of service.", Type: []string{"string"}, Format: "", }, }, - "ethertype": { + "type": { SchemaProps: spec.SchemaProps{ - Description: "ethertype must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules.", + Description: "type indicates which resource the service is responsible for.", Type: []string{"string"}, Format: "", }, }, - "portRange": { + "enabled": { SchemaProps: spec.SchemaProps{ - Description: "portRange sets the minimum and maximum ports range that the security group rule matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than or equal to the PortRange.Max attribute value. If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max should be an ICMP type", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeStatus"), + Description: "enabled indicates whether the service is enabled or not.", + Type: []string{"boolean"}, + Format: "", }, }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.PortRangeStatus"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupSpec defines the desired state of an ORC object.", + Description: "ServiceSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceSpec"), }, }, "managementPolicy": { @@ -7316,6 +11222,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupSpec(ref Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -7328,15 +11240,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupSpec(ref }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SecurityGroupStatus defines the observed state of an ORC resource.", + Description: "ServiceStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -7373,22 +11285,28 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SecurityGroupStatus(re "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SecurityGroupResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_Server(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetwork(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Server is the Schema for an ORC resource.", + Description: "ShareNetwork is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -7416,29 +11334,30 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Server(ref common.Refe SchemaProps: spec.SchemaProps{ Description: "spec specifies the desired state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ Description: "status defines the observed state of the resource.", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkStatus"), }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerFilter defines an existing resource by its properties", + Description: "ShareNetworkFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -7448,159 +11367,9 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerFilter(ref commo Format: "", }, }, - "availabilityZone": { - SchemaProps: spec.SchemaProps{ - Description: "availabilityZone is the availability zone of the existing resource", - Type: []string{"string"}, - Format: "", - }, - }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "tagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "notTags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "notTagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServerGroup is the Schema for an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServerGroupFilter defines an existing resource by its properties", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", + Description: "description of the existing resource", Type: []string{"string"}, Format: "", }, @@ -7611,11 +11380,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupFilter(ref } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerGroupImport specifies an existing resource which will be imported instead of creating a new one", + Description: "ShareNetworkImport specifies an existing resource which will be imported instead of creating a new one", Type: []string{"object"}, Properties: map[string]spec.Schema{ "id": { @@ -7628,22 +11397,22 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupImport(ref "filter": { SchemaProps: spec.SchemaProps{ Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupFilter"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerGroupList contains a list of ServerGroup.", + Description: "ShareNetworkList contains a list of ShareNetwork.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -7669,13 +11438,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupList(ref co }, "items": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of ServerGroup.", + Description: "items contains a list of ShareNetwork.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroup"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetwork"), }, }, }, @@ -7686,15 +11455,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupList(ref co }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroup", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetwork", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerGroupResourceSpec contains the desired state of a servergroup", + Description: "ShareNetworkResourceSpec contains the desired state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -7704,132 +11473,141 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceSpe Format: "", }, }, - "policy": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "policy is the policy to use for the server group.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "rules": { + "networkRef": { SchemaProps: spec.SchemaProps{ - Description: "rules is the rules to use for the server group.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRules"), + Description: "networkRef is a reference to the ORC Network which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + "subnetRef": { + SchemaProps: spec.SchemaProps{ + Description: "subnetRef is a reference to the ORC Subnet which this resource is associated with.", + Type: []string{"string"}, + Format: "", }, }, }, - Required: []string{"policy"}, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRules"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerGroupResourceStatus represents the observed state of the resource.", + Description: "ShareNetworkResourceStatus represents the observed state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the servergroup. Might not be unique.", + Description: "name is a Human-readable name for the resource.", Type: []string{"string"}, Format: "", }, }, - "policy": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "policy is the policy of the servergroup.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "projectID": { + "neutronNetID": { SchemaProps: spec.SchemaProps{ - Description: "projectID is the project owner of the resource.", + Description: "neutronNetID is the Neutron network ID.", Type: []string{"string"}, Format: "", }, }, - "userID": { + "neutronSubnetID": { SchemaProps: spec.SchemaProps{ - Description: "userID of the server group.", + Description: "neutronSubnetID is the Neutron subnet ID.", Type: []string{"string"}, Format: "", }, }, - "rules": { + "networkType": { SchemaProps: spec.SchemaProps{ - Description: "rules is the rules of the server group.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRulesStatus"), + Description: "networkType is the network type (e.g., vlan, vxlan, flat).", + Type: []string{"string"}, + Format: "", }, }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupRulesStatus"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRules(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "maxServerPerHost": { + "segmentationID": { SchemaProps: spec.SchemaProps{ - Description: "maxServerPerHost specifies how many servers can reside on a single compute host. It can be used only with the \"anti-affinity\" policy.", + Description: "segmentationID is the segmentation ID of the network.", Type: []string{"integer"}, Format: "int32", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupRulesStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "maxServerPerHost": { + "cidr": { SchemaProps: spec.SchemaProps{ - Description: "maxServerPerHost specifies how many servers can reside on a single compute host. It can be used only with the \"anti-affinity\" policy.", + Description: "cidr is the CIDR of the subnet.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "ipVersion": { + SchemaProps: spec.SchemaProps{ + Description: "ipVersion is the IP version (4 or 6).", Type: []string{"integer"}, Format: "int32", }, }, + "projectID": { + SchemaProps: spec.SchemaProps{ + Description: "projectID is the ID of the project that owns the share network.", + Type: []string{"string"}, + Format: "", + }, + }, + "createdAt": { + SchemaProps: spec.SchemaProps{ + Description: "createdAt shows the date and time when the resource was created.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "updatedAt": { + SchemaProps: spec.SchemaProps{ + Description: "updatedAt shows the date and time when the resource was updated.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, }, }, }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerGroupSpec defines the desired state of an ORC object.", + Description: "ShareNetworkSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkResourceSpec"), }, }, "managementPolicy": { @@ -7845,6 +11623,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupSpec(ref co Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -7857,15 +11641,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupSpec(ref co }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_ShareNetworkStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerGroupStatus defines the observed state of an ORC resource.", + Description: "ShareNetworkStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -7902,137 +11686,285 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerGroupStatus(ref "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerGroupResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ShareNetworkResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_Subnet(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerImport specifies an existing resource which will be imported instead of creating a new one", + Description: "Subnet is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { + "kind": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SubnetFilter specifies a filter to select a subnet. At least one parameter must be specified.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "ipVersion": { + SchemaProps: spec.SchemaProps{ + Description: "ipVersion of the existing resource", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "gatewayIP": { + SchemaProps: spec.SchemaProps{ + Description: "gatewayIP is the IP address of the gateway of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "cidr": { + SchemaProps: spec.SchemaProps{ + Description: "cidr of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "ipv6": { + SchemaProps: spec.SchemaProps{ + Description: "ipv6 options of the existing resource", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options"), + }, + }, + "networkRef": { + SchemaProps: spec.SchemaProps{ + Description: "networkRef is a reference to the ORC Network which this subnet is associated with.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "projectRef": { + SchemaProps: spec.SchemaProps{ + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", Type: []string{"string"}, Format: "", }, }, - "filter": { + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "notTagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerFilter"), + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceFixedIP(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetGateway(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "ipAddress": { + "type": { SchemaProps: spec.SchemaProps{ - Description: "ipAddress is the IP address assigned to the port.", + Description: "type specifies how the default gateway will be created. `Automatic` specifies that neutron will automatically add a default gateway. This is also the default if no Gateway is specified. `None` specifies that the subnet will not have a default gateway. `IP` specifies that the subnet will use a specific address as the default gateway, which must be specified in `IP`.", Type: []string{"string"}, Format: "", }, }, - "subnetID": { + "ip": { SchemaProps: spec.SchemaProps{ - Description: "subnetID is the ID of the subnet from which the IP address is allocated.", + Description: "ip is the IP address of the default gateway, which must be specified if Type is `IP`. It must be a valid IP address, either IPv4 or IPv6, matching the IPVersion in SubnetResourceSpec.", Type: []string{"string"}, Format: "", }, }, }, + Required: []string{"type"}, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerInterfaceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "SubnetImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "portID": { - SchemaProps: spec.SchemaProps{ - Description: "portID is the ID of a port attached to the server.", - Type: []string{"string"}, - Format: "", - }, - }, - "netID": { - SchemaProps: spec.SchemaProps{ - Description: "netID is the ID of the network to which the interface is attached.", - Type: []string{"string"}, - Format: "", - }, - }, - "macAddr": { - SchemaProps: spec.SchemaProps{ - Description: "macAddr is the MAC address of the interface.", - Type: []string{"string"}, - Format: "", - }, - }, - "portState": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "portState is the state of the port (e.g., ACTIVE, DOWN).", + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, - "fixedIPs": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "filter": { SchemaProps: spec.SchemaProps{ - Description: "fixedIPs is the list of fixed IP addresses assigned to the interface.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceFixedIP"), - }, - }, - }, + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceFixedIP"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerList contains a list of Server.", + Description: "SubnetList contains a list of Subnet.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -8058,13 +11990,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerList(ref common. }, "items": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Server.", + Description: "items contains a list of Subnet.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Server"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Subnet"), }, }, }, @@ -8075,130 +12007,112 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerList(ref common. }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Server", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Subnet", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerPortSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "portRef": { - SchemaProps: spec.SchemaProps{ - Description: "portRef is a reference to a Port object. Server creation will wait for this port to be created and available.", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServerResourceSpec contains the desired state of a server", - Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Description: "name is a human-readable name of the subnet. If not set, the object's name will be used.", Type: []string{"string"}, Format: "", }, }, - "imageRef": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "imageRef references the image to use for the server instance. NOTE: This is not required in case of boot from volume.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "flavorRef": { + "networkRef": { SchemaProps: spec.SchemaProps{ - Description: "flavorRef references the flavor to use for the server instance.", + Description: "networkRef is a reference to the ORC Network which this subnet is associated with.", Type: []string{"string"}, Format: "", }, }, - "userData": { - SchemaProps: spec.SchemaProps{ - Description: "userData specifies data which will be made available to the server at boot time, either via the metadata service or a config drive. It is typically read by a configuration service such as cloud-init or ignition.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserDataSpec"), - }, - }, - "ports": { + "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", + "x-kubernetes-list-type": "set", }, }, SchemaProps: spec.SchemaProps{ - Description: "ports defines a list of ports which will be attached to the server.", + Description: "tags is a list of tags which will be applied to the subnet.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerPortSpec"), + Default: "", + Type: []string{"string"}, + Format: "", }, }, }, }, }, - "volumes": { + "ipVersion": { + SchemaProps: spec.SchemaProps{ + Description: "ipVersion is the IP version for the subnet.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "cidr": { + SchemaProps: spec.SchemaProps{ + Description: "cidr is the address CIDR of the subnet. It must match the IP version specified in IPVersion.", + Type: []string{"string"}, + Format: "", + }, + }, + "allocationPools": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "volumes is a list of volumes attached to the server.", + Description: "allocationPools are IP Address pools that will be available for DHCP. IP addresses must be in CIDR.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPool"), }, }, }, }, }, - "serverGroupRef": { - SchemaProps: spec.SchemaProps{ - Description: "serverGroupRef is a reference to a ServerGroup object. The server will be created in the server group.", - Type: []string{"string"}, - Format: "", - }, - }, - "availabilityZone": { + "gateway": { SchemaProps: spec.SchemaProps{ - Description: "availabilityZone is the availability zone in which to create the server.", - Type: []string{"string"}, - Format: "", + Description: "gateway specifies the default gateway of the subnet. If not specified, neutron will add one automatically. To disable this behaviour, specify a gateway with a type of None.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetGateway"), }, }, - "keypairRef": { + "enableDHCP": { SchemaProps: spec.SchemaProps{ - Description: "keypairRef is a reference to a KeyPair object. The server will be created with this keypair for SSH access.", - Type: []string{"string"}, + Description: "enableDHCP will either enable to disable the DHCP service.", + Type: []string{"boolean"}, Format: "", }, }, - "tags": { + "dnsNameservers": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "set", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the server.", + Description: "dnsNameservers are the nameservers to be set via DHCP.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8211,65 +12125,110 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceSpec(ref }, }, }, + "dnsPublishFixedIP": { + SchemaProps: spec.SchemaProps{ + Description: "dnsPublishFixedIP will either enable or disable the publication of fixed IPs to the DNS. Defaults to false.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "hostRoutes": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "hostRoutes are any static host routes to be set via DHCP.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRoute"), + }, + }, + }, + }, + }, + "ipv6": { + SchemaProps: spec.SchemaProps{ + Description: "ipv6 contains IPv6-specific options. It may only be set if IPVersion is 6.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options"), + }, + }, + "routerRef": { + SchemaProps: spec.SchemaProps{ + Description: "routerRef specifies a router to attach the subnet to", + Type: []string{"string"}, + Format: "", + }, + }, + "projectRef": { + SchemaProps: spec.SchemaProps{ + Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"imageRef", "flavorRef", "ports"}, + Required: []string{"networkRef", "ipVersion", "cidr"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerPortSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserDataSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPool", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRoute", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetGateway"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServerResourceStatus represents the observed state of the resource.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name is the human-readable name of the resource. Might not be unique.", + Description: "name is the human-readable name of the subnet. Might not be unique.", Type: []string{"string"}, Format: "", }, }, - "hostID": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "hostID is the host where the server is located in the cloud.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "status": { + "ipVersion": { SchemaProps: spec.SchemaProps{ - Description: "status contains the current operational status of the server, such as IN_PROGRESS or ACTIVE.", - Type: []string{"string"}, - Format: "", + Description: "ipVersion specifies IP version, either `4' or `6'.", + Type: []string{"integer"}, + Format: "int32", }, }, - "imageID": { + "cidr": { SchemaProps: spec.SchemaProps{ - Description: "imageID indicates the OS image used to deploy the server.", + Description: "cidr representing IP range for this subnet, based on IP version.", Type: []string{"string"}, Format: "", }, }, - "availabilityZone": { + "gatewayIP": { SchemaProps: spec.SchemaProps{ - Description: "availabilityZone is the availability zone where the server is located.", + Description: "gatewayIP is the default gateway used by devices in this subnet, if any.", Type: []string{"string"}, Format: "", }, }, - "serverGroups": { + "dnsNameservers": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "serverGroups is a slice of strings containing the UUIDs of the server groups to which the server belongs. Currently this can contain at most one entry.", + Description: "dnsNameservers is a list of name servers used by hosts in this subnet.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8282,562 +12241,464 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ServerResourceStatus(r }, }, }, - "volumes": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "dnsPublishFixedIP": { SchemaProps: spec.SchemaProps{ - Description: "volumes contains the volumes attached to the server.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeStatus"), - }, - }, - }, + Description: "dnsPublishFixedIP specifies whether the fixed IP addresses are published to the DNS.", + Type: []string{"boolean"}, + Format: "", }, }, - "interfaces": { + "allocationPools": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "interfaces contains the list of interfaces attached to the server.", + Description: "allocationPools is a list of sub-ranges within CIDR available for dynamic allocation to ports.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPoolStatus"), }, }, }, }, }, - "tags": { + "hostRoutes": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is the list of tags on the resource.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerInterfaceStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerVolumeStatus"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServerSpec defines the desired state of an ORC object.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "import": { - SchemaProps: spec.SchemaProps{ - Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerImport"), - }, - }, - "resource": { - SchemaProps: spec.SchemaProps{ - Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceSpec"), - }, - }, - "managementPolicy": { - SchemaProps: spec.SchemaProps{ - Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", - Type: []string{"string"}, - Format: "", - }, - }, - "managedOptions": { - SchemaProps: spec.SchemaProps{ - Description: "managedOptions specifies options which may be applied to managed objects.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), - }, - }, - "cloudCredentialsRef": { - SchemaProps: spec.SchemaProps{ - Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), - }, - }, - }, - Required: []string{"cloudCredentialsRef"}, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceSpec"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServerStatus defines the observed state of an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Description: "hostRoutes is a list of routes that should be used by devices with IPs from this subnet (not including local subnet route).", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRouteStatus"), }, }, }, }, }, - "id": { + "enableDHCP": { SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", - Type: []string{"string"}, + Description: "enableDHCP specifies whether DHCP is enabled for this subnet or not.", + Type: []string{"boolean"}, Format: "", }, }, - "resource": { - SchemaProps: spec.SchemaProps{ - Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServerResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "volumeRef": { + "networkID": { SchemaProps: spec.SchemaProps{ - Description: "volumeRef is a reference to a Volume object. Server creation will wait for this volume to be created and available.", + Description: "networkID is the ID of the network to which the subnet belongs.", Type: []string{"string"}, Format: "", }, }, - "device": { + "projectID": { SchemaProps: spec.SchemaProps{ - Description: "device is the name of the device, such as `/dev/vdb`. Omit for auto-assignment", + Description: "projectID is the project owner of the subnet.", Type: []string{"string"}, Format: "", }, }, - }, - Required: []string{"volumeRef"}, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServerVolumeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "id": { + "ipv6AddressMode": { SchemaProps: spec.SchemaProps{ - Description: "id is the ID of a volume attached to the server.", + Description: "ipv6AddressMode specifies mechanisms for assigning IPv6 IP addresses.", Type: []string{"string"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_Service(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Service is the Schema for an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { + "ipv6RAMode": { SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Description: "ipv6RAMode is the IPv6 router advertisement mode. It specifies whether the networking service should transmit ICMPv6 packets.", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "subnetPoolID": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "subnetPoolID is the id of the subnet pool associated with the subnet.", Type: []string{"string"}, Format: "", }, }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, }, - }, - "spec": { SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceSpec"), + Description: "tags optionally set via extensions/attributestags", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "status": { + "createdAt": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceStatus"), + Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServiceFilter defines an existing resource by its properties", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", - Type: []string{"string"}, - Format: "", + "updatedAt": { + SchemaProps: spec.SchemaProps{ + Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "type": { + "revisionNumber": { SchemaProps: spec.SchemaProps{ - Description: "type of the existing resource", - Type: []string{"string"}, - Format: "", + Description: "revisionNumber optionally set via extensions/standard-attr-revisions", + Type: []string{"integer"}, + Format: "int64", }, }, }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPoolStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRouteStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServiceImport specifies an existing resource which will be imported instead of creating a new one", + Description: "SubnetSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { + "import": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", Type: []string{"string"}, Format: "", }, }, - "filter": { + "managedOptions": { SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceFilter"), + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), }, }, }, + Required: []string{"cloudCredentialsRef"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceFilter"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServiceList contains a list of Service.", + Description: "SubnetStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "kind": { + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, }, }, - "apiVersion": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Description: "id is the unique identifier of the OpenStack resource.", Type: []string{"string"}, Format: "", }, }, - "metadata": { + "resource": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceStatus"), }, }, - "items": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Service.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Service"), - }, - }, - }, + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, - Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Service", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_Trunk(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServiceResourceSpec contains the desired state of the resource.", + Description: "Trunk is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "kind": { SchemaProps: spec.SchemaProps{ - Description: "name indicates the name of service. If not specified, the name of the ORC resource will be used.", + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", Type: []string{"string"}, Format: "", }, }, - "description": { + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "description indicates the description of service.", + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, - "type": { + "metadata": { SchemaProps: spec.SchemaProps{ - Description: "type indicates which resource the service is responsible for.", - Type: []string{"string"}, - Format: "", + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, - "enabled": { + "spec": { SchemaProps: spec.SchemaProps{ - Description: "enabled indicates whether the service is enabled or not.", - Type: []string{"boolean"}, - Format: "", + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkStatus"), }, }, }, - Required: []string{"type"}, + Required: []string{"spec"}, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ServiceResourceStatus represents the observed state of the resource.", + Description: "TrunkFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name indicates the name of service.", + Description: "name of the existing resource", Type: []string{"string"}, Format: "", }, }, "description": { SchemaProps: spec.SchemaProps{ - Description: "description indicates the description of service.", + Description: "description of the existing resource", Type: []string{"string"}, Format: "", }, }, - "type": { + "portRef": { SchemaProps: spec.SchemaProps{ - Description: "type indicates which resource the service is responsible for.", + Description: "portRef is a reference to the ORC Port which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, - "enabled": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "enabled indicates whether the service is enabled or not.", - Type: []string{"boolean"}, + Description: "projectRef is a reference to the ORC Project which this resource is associated with.", + Type: []string{"string"}, Format: "", }, }, - }, - }, - }, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServiceSpec defines the desired state of an ORC object.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "import": { + "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceImport"), + Description: "adminStateUp is the administrative state of the trunk.", + Type: []string{"boolean"}, + Format: "", }, }, - "resource": { - SchemaProps: spec.SchemaProps{ - Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceSpec"), + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, }, - }, - "managementPolicy": { SchemaProps: spec.SchemaProps{ - Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", - Type: []string{"string"}, - Format: "", + Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "managedOptions": { + "tagsAny": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "managedOptions specifies options which may be applied to managed objects.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - "cloudCredentialsRef": { + "notTags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, - }, - Required: []string{"cloudCredentialsRef"}, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceSpec"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_ServiceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ServiceStatus defines the observed state of an ORC resource.", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "conditions": { + "notTagsAny": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "type", - }, - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge", + "x-kubernetes-list-type": "set", }, }, SchemaProps: spec.SchemaProps{ - Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + Default: "", + Type: []string{"string"}, + Format: "", }, }, }, }, }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TrunkImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ "id": { SchemaProps: spec.SchemaProps{ - Description: "id is the unique identifier of the OpenStack resource.", + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, - "resource": { + "filter": { SchemaProps: spec.SchemaProps{ - Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceStatus"), + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkFilter"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ServiceResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_Subnet(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Subnet is the Schema for an ORC resource.", + Description: "TrunkList contains a list of Trunk.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -8856,92 +12717,169 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Subnet(ref common.Refe }, "metadata": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the object metadata", - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Description: "spec specifies the desired state of the resource.", + Description: "metadata contains the list metadata", Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetSpec"), + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, }, - "status": { + "items": { SchemaProps: spec.SchemaProps{ - Description: "status defines the observed state of the resource.", - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetStatus"), + Description: "items contains a list of Trunk.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Trunk"), + }, + }, + }, }, }, }, + Required: []string{"items"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Trunk", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SubnetFilter specifies a filter to select a subnet. At least one parameter must be specified.", + Description: "TrunkResourceSpec contains the desired state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", Type: []string{"string"}, Format: "", }, }, "description": { SchemaProps: spec.SchemaProps{ - Description: "description of the existing resource", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "ipVersion": { + "portRef": { SchemaProps: spec.SchemaProps{ - Description: "ipVersion of the existing resource", - Type: []string{"integer"}, - Format: "int32", + Description: "portRef is a reference to the ORC Port which this resource is associated with.", + Type: []string{"string"}, + Format: "", }, }, - "gatewayIP": { + "projectRef": { SchemaProps: spec.SchemaProps{ - Description: "gatewayIP is the IP address of the gateway of the existing resource", + Description: "projectRef is a reference to the ORC Project which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, - "cidr": { + "adminStateUp": { SchemaProps: spec.SchemaProps{ - Description: "cidr of the existing resource", + Description: "adminStateUp is the administrative state of the trunk. If false (down), the trunk does not forward packets.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "subports": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "subports is the list of ports to attach to the trunk.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSubportSpec"), + }, + }, + }, + }, + }, + "tags": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "tags is a list of Neutron tags to apply to the trunk.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"portRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSubportSpec"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TrunkResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the resource. Might not be unique.", Type: []string{"string"}, Format: "", }, }, - "ipv6": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "ipv6 options of the existing resource", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options"), + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", }, }, - "networkRef": { + "portID": { SchemaProps: spec.SchemaProps{ - Description: "networkRef is a reference to the ORC Network which this subnet is associated with.", - Default: "", + Description: "portID is the ID of the Port to which the resource is associated.", Type: []string{"string"}, Format: "", }, }, - "projectRef": { + "projectID": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "projectID is the ID of the Project to which the resource is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + "tenantID": { + SchemaProps: spec.SchemaProps{ + Description: "tenantID is the project owner of the trunk (alias of projectID in some deployments).", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status indicates whether the trunk is currently operational.", Type: []string{"string"}, Format: "", }, @@ -8949,11 +12887,11 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetFilter(ref commo "tags": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.", + Description: "tags is the list of tags on the resource.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8966,134 +12904,245 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetFilter(ref commo }, }, }, - "tagsAny": { + "createdAt": { + SchemaProps: spec.SchemaProps{ + Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "updatedAt": { + SchemaProps: spec.SchemaProps{ + Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "revisionNumber": { + SchemaProps: spec.SchemaProps{ + Description: "revisionNumber optionally set via extensions/standard-attr-revisions", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "adminStateUp": { + SchemaProps: spec.SchemaProps{ + Description: "adminStateUp is the administrative state of the trunk.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "subports": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-type": "atomic", }, }, SchemaProps: spec.SchemaProps{ - Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.", + Description: "subports is a list of ports associated with the trunk.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSubportStatus"), }, }, }, }, }, - "notTags": { + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkSubportStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TrunkSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TrunkStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", }, }, SchemaProps: spec.SchemaProps{ - Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.", + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), }, }, }, }, }, - "notTagsAny": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", }, + }, + "resource": { SchemaProps: spec.SchemaProps{ - Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.TrunkResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetGateway(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkSubportSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "TrunkSubportSpec represents a subport to attach to a trunk. It maps to gophercloud's trunks.Subport.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "type": { + "portRef": { SchemaProps: spec.SchemaProps{ - Description: "type specifies how the default gateway will be created. `Automatic` specifies that neutron will automatically add a default gateway. This is also the default if no Gateway is specified. `None` specifies that the subnet will not have a default gateway. `IP` specifies that the subnet will use a specific address as the default gateway, which must be specified in `IP`.", + Description: "portRef is a reference to the ORC Port that will be attached as a subport.", Type: []string{"string"}, Format: "", }, }, - "ip": { + "segmentationID": { SchemaProps: spec.SchemaProps{ - Description: "ip is the IP address of the default gateway, which must be specified if Type is `IP`. It must be a valid IP address, either IPv4 or IPv6, matching the IPVersion in SubnetResourceSpec.", + Description: "segmentationID is the segmentation ID for the subport (e.g. VLAN ID).", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "segmentationType": { + SchemaProps: spec.SchemaProps{ + Description: "segmentationType is the segmentation type for the subport (e.g. vlan).", Type: []string{"string"}, Format: "", }, }, }, - Required: []string{"type"}, + Required: []string{"portRef", "segmentationID", "segmentationType"}, }, }, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetImport(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_TrunkSubportStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SubnetImport specifies an existing resource which will be imported instead of creating a new one", + Description: "TrunkSubportStatus represents an attached subport on a trunk. It maps to gophercloud's trunks.Subport.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "id": { + "portID": { SchemaProps: spec.SchemaProps{ - Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Description: "portID is the OpenStack ID of the Port attached as a subport.", Type: []string{"string"}, Format: "", }, }, - "filter": { + "segmentationID": { SchemaProps: spec.SchemaProps{ - Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetFilter"), + Description: "segmentationID is the segmentation ID for the subport (e.g. VLAN ID).", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "segmentationType": { + SchemaProps: spec.SchemaProps{ + Description: "segmentationType is the segmentation type for the subport (e.g. vlan).", + Type: []string{"string"}, + Format: "", }, }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetFilter"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetList(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_User(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SubnetList contains a list of Subnet.", + Description: "User is the Schema for an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { @@ -9112,415 +13161,293 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetList(ref common. }, "metadata": { SchemaProps: spec.SchemaProps{ - Description: "metadata contains the list metadata", + Description: "metadata contains the object metadata", Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, - "items": { + "spec": { SchemaProps: spec.SchemaProps{ - Description: "items contains a list of Subnet.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Subnet"), - }, - }, - }, + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserStatus"), }, }, }, - Required: []string{"items"}, + Required: []string{"spec"}, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Subnet", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_UserDataSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is a human-readable name of the subnet. If not set, the object's name will be used.", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { - SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", - Type: []string{"string"}, - Format: "", - }, - }, - "networkRef": { - SchemaProps: spec.SchemaProps{ - Description: "networkRef is a reference to the ORC Network which this subnet is associated with.", - Type: []string{"string"}, - Format: "", - }, - }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "tags is a list of tags which will be applied to the subnet.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "ipVersion": { - SchemaProps: spec.SchemaProps{ - Description: "ipVersion is the IP version for the subnet.", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - "cidr": { + "secretRef": { SchemaProps: spec.SchemaProps{ - Description: "cidr is the address CIDR of the subnet. It must match the IP version specified in IPVersion.", + Description: "secretRef is a reference to a Secret containing the user data for this server.", Type: []string{"string"}, Format: "", }, }, - "allocationPools": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "allocationPools are IP Address pools that will be available for DHCP. IP addresses must be in CIDR.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPool"), - }, - }, - }, - }, - }, - "gateway": { - SchemaProps: spec.SchemaProps{ - Description: "gateway specifies the default gateway of the subnet. If not specified, neutron will add one automatically. To disable this behaviour, specify a gateway with a type of None.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetGateway"), - }, - }, - "enableDHCP": { - SchemaProps: spec.SchemaProps{ - Description: "enableDHCP will either enable to disable the DHCP service.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "dnsNameservers": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "set", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "dnsNameservers are the nameservers to be set via DHCP.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "dnsPublishFixedIP": { - SchemaProps: spec.SchemaProps{ - Description: "dnsPublishFixedIP will either enable or disable the publication of fixed IPs to the DNS. Defaults to false.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "hostRoutes": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "hostRoutes are any static host routes to be set via DHCP.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRoute"), - }, - }, - }, - }, - }, - "ipv6": { - SchemaProps: spec.SchemaProps{ - Description: "ipv6 contains IPv6-specific options. It may only be set if IPVersion is 6.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options"), - }, - }, - "routerRef": { + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_UserFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "UserFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { SchemaProps: spec.SchemaProps{ - Description: "routerRef specifies a router to attach the subnet to", + Description: "name of the existing resource", Type: []string{"string"}, Format: "", }, }, - "projectRef": { + "domainRef": { SchemaProps: spec.SchemaProps{ - Description: "projectRef is a reference to the ORC Project this resource is associated with. Typically, only used by admin.", + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, }, - Required: []string{"networkRef", "ipVersion", "cidr"}, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPool", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRoute", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.IPv6Options", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetGateway"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_UserImport(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "UserImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { - SchemaProps: spec.SchemaProps{ - Description: "name is the human-readable name of the subnet. Might not be unique.", - Type: []string{"string"}, - Format: "", - }, - }, - "description": { + "id": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", Type: []string{"string"}, Format: "", }, }, - "ipVersion": { + "filter": { SchemaProps: spec.SchemaProps{ - Description: "ipVersion specifies IP version, either `4' or `6'.", - Type: []string{"integer"}, - Format: "int32", + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserFilter"), }, }, - "cidr": { + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_UserList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "UserList contains a list of User.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { SchemaProps: spec.SchemaProps{ - Description: "cidr representing IP range for this subnet, based on IP version.", + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", Type: []string{"string"}, Format: "", }, }, - "gatewayIP": { + "apiVersion": { SchemaProps: spec.SchemaProps{ - Description: "gatewayIP is the default gateway used by devices in this subnet, if any.", + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, - "dnsNameservers": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, + }, + "items": { SchemaProps: spec.SchemaProps{ - Description: "dnsNameservers is a list of name servers used by hosts in this subnet.", + Description: "items contains a list of User.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.User"), }, }, }, }, }, - "dnsPublishFixedIP": { + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.User", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_UserResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "UserResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { SchemaProps: spec.SchemaProps{ - Description: "dnsPublishFixedIP specifies whether the fixed IP addresses are published to the DNS.", - Type: []string{"boolean"}, + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, Format: "", }, }, - "allocationPools": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "description": { SchemaProps: spec.SchemaProps{ - Description: "allocationPools is a list of sub-ranges within CIDR available for dynamic allocation to ports.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPoolStatus"), - }, - }, - }, + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", }, }, - "hostRoutes": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "domainRef": { SchemaProps: spec.SchemaProps{ - Description: "hostRoutes is a list of routes that should be used by devices with IPs from this subnet (not including local subnet route).", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRouteStatus"), - }, - }, - }, + Description: "domainRef is a reference to the ORC Domain which this resource is associated with.", + Type: []string{"string"}, + Format: "", }, }, - "enableDHCP": { + "defaultProjectRef": { SchemaProps: spec.SchemaProps{ - Description: "enableDHCP specifies whether DHCP is enabled for this subnet or not.", - Type: []string{"boolean"}, + Description: "defaultProjectRef is a reference to the Default Project which this resource is associated with.", + Type: []string{"string"}, Format: "", }, }, - "networkID": { + "enabled": { SchemaProps: spec.SchemaProps{ - Description: "networkID is the ID of the network to which the subnet belongs.", - Type: []string{"string"}, + Description: "enabled defines whether a user is enabled or disabled", + Type: []string{"boolean"}, Format: "", }, }, - "projectID": { + "passwordRef": { SchemaProps: spec.SchemaProps{ - Description: "projectID is the project owner of the subnet.", + Description: "passwordRef is a reference to a Secret containing the password for this user. The Secret must contain a key named \"password\". If not specified, the user is created without a password.", Type: []string{"string"}, Format: "", }, }, - "ipv6AddressMode": { + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_UserResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "UserResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { SchemaProps: spec.SchemaProps{ - Description: "ipv6AddressMode specifies mechanisms for assigning IPv6 IP addresses.", + Description: "name is a Human-readable name for the resource. Might not be unique.", Type: []string{"string"}, Format: "", }, }, - "ipv6RAMode": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "ipv6RAMode is the IPv6 router advertisement mode. It specifies whether the networking service should transmit ICMPv6 packets.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "subnetPoolID": { + "domainID": { SchemaProps: spec.SchemaProps{ - Description: "subnetPoolID is the id of the subnet pool associated with the subnet.", + Description: "domainID is the ID of the Domain to which the resource is associated.", Type: []string{"string"}, Format: "", }, }, - "tags": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, + "defaultProjectID": { SchemaProps: spec.SchemaProps{ - Description: "tags optionally set via extensions/attributestags", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "defaultProjectID is the ID of the Default Project to which the user is associated with.", + Type: []string{"string"}, + Format: "", }, }, - "createdAt": { + "enabled": { SchemaProps: spec.SchemaProps{ - Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "enabled defines whether a user is enabled or disabled", + Type: []string{"boolean"}, + Format: "", }, }, - "updatedAt": { + "passwordExpiresAt": { SchemaProps: spec.SchemaProps{ - Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "passwordExpiresAt is the timestamp at which the user's password expires.", + Type: []string{"string"}, + Format: "", }, }, - "revisionNumber": { + "appliedPasswordRef": { SchemaProps: spec.SchemaProps{ - Description: "revisionNumber optionally set via extensions/standard-attr-revisions", - Type: []string{"integer"}, - Format: "int64", + Description: "appliedPasswordRef is the name of the Secret containing the password that was last applied to the OpenStack resource.", + Type: []string{"string"}, + Format: "", }, }, }, }, }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.AllocationPoolStatus", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.HostRouteStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_UserSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SubnetSpec defines the desired state of an ORC object.", + Description: "UserSpec defines the desired state of an ORC object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "import": { SchemaProps: spec.SchemaProps{ Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetImport"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserImport"), }, }, "resource": { SchemaProps: spec.SchemaProps{ Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceSpec"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserResourceSpec"), }, }, "managementPolicy": { @@ -9536,6 +13463,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetSpec(ref common. Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -9548,15 +13481,15 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetSpec(ref common. }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } -func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_openstack_resource_controller_v2_api_v1alpha1_UserStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SubnetStatus defines the observed state of an ORC resource.", + Description: "UserStatus defines the observed state of an ORC resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "conditions": { @@ -9593,33 +13526,20 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetStatus(ref commo "resource": { SchemaProps: spec.SchemaProps{ Description: "resource contains the observed state of the OpenStack resource.", - Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceStatus"), + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserResourceStatus"), }, }, - }, - }, - }, - Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, - } -} - -func schema_openstack_resource_controller_v2_api_v1alpha1_UserDataSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "secretRef": { + "lastSyncTime": { SchemaProps: spec.SchemaProps{ - Description: "secretRef is a reference to a Secret containing the user data for this server.", - Type: []string{"string"}, - Format: "", + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, }, }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.UserResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } @@ -9666,6 +13586,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_Volume(ref common.Refe }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ @@ -9953,6 +13874,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeResourceSpec(ref }, }, }, + "imageRef": { + SchemaProps: spec.SchemaProps{ + Description: "imageRef is a reference to an ORC Image. If specified, creates a bootable volume from this image. The volume size must be >= the image's min_disk requirement.", + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"size"}, }, @@ -10084,6 +14012,13 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeResourceStatus(r Format: "", }, }, + "imageID": { + SchemaProps: spec.SchemaProps{ + Description: "imageID is the ID of the image this volume was created from, if any.", + Type: []string{"string"}, + Format: "", + }, + }, "encrypted": { SchemaProps: spec.SchemaProps{ Description: "encrypted denotes if the volume is encrypted.", @@ -10178,6 +14113,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeSpec(ref common. Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -10190,7 +14131,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeSpec(ref common. }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } @@ -10238,11 +14179,17 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeStatus(ref commo Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceStatus"), }, }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } @@ -10289,6 +14236,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeType(ref common. }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ @@ -10606,6 +14554,12 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeSpec(ref com Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), }, }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, "cloudCredentialsRef": { SchemaProps: spec.SchemaProps{ Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", @@ -10618,7 +14572,7 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeSpec(ref com }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceSpec"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, } } @@ -10666,11 +14620,17 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_VolumeTypeStatus(ref c Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceStatus"), }, }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.VolumeTypeResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } diff --git a/cmd/resource-generator/data/adapter.template b/cmd/resource-generator/data/adapter.template index 30e7ec827..6e9c61023 100644 --- a/cmd/resource-generator/data/adapter.template +++ b/cmd/resource-generator/data/adapter.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ limitations under the License. package {{ .NameLower }} import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -54,8 +56,20 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { +{{- if .NoResourceID }} + return nil +{{- else }} return f.Status.ID +{{- end }} } func (f adapterT) GetResourceSpec() *resourceSpecT { @@ -63,10 +77,14 @@ func (f adapterT) GetResourceSpec() *resourceSpecT { } func (f adapterT) GetImportID() *string { +{{- if .NoResourceID }} + return nil +{{- else }} if f.Spec.Import == nil { return nil } return f.Spec.Import.ID +{{- end }} } func (f adapterT) GetImportFilter() *filterT { diff --git a/cmd/resource-generator/data/api.template b/cmd/resource-generator/data/api.template index 1abe2bf30..6018a9aa5 100644 --- a/cmd/resource-generator/data/api.template +++ b/cmd/resource-generator/data/api.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,22 +23,28 @@ import ( // {{ .Name }}Import specifies an existing resource which will be imported instead of // creating a new one // +kubebuilder:validation:MinProperties:=1 +{{- if not .NoResourceID }} // +kubebuilder:validation:MaxProperties:=1 +{{- end }} type {{ .Name }}Import struct { +{{- if not .NoResourceID }} {{- if .UsesNameAsID }} // id contains the name of an existing resource. Note: This resource uses // the resource name as the unique identifier, not a UUID. // When specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:MaxLength:=1024 // +optional - ID *string `json:"id,omitempty"` + ID *string `json:"id,omitempty"` //nolint:kubeapilinter {{- else }} // id contains the unique identifier of an existing OpenStack resource. Note // that when specifying an import by ID, the resource MUST already exist. // The ORC object will enter an error state if the resource does not exist. - // +optional // +kubebuilder:validation:Format:=uuid - ID *string `json:"id,omitempty"` + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter +{{- end }} {{- end }} // filter contains a resource query which is expected to return a single @@ -88,9 +94,17 @@ type {{ .Name }}Spec struct { // +optional ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + // cloudCredentialsRef points to a secret containing OpenStack credentials // +required - CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef"` + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` } // {{ .Name }}Status defines the observed state of an ORC resource. @@ -116,14 +130,24 @@ type {{ .Name }}Status struct { // +listMapKey=type // +optional Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` +{{- if not .NoResourceID }} // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 // +optional ID *string `json:"id,omitempty"` +{{- end }} // resource contains the observed state of the OpenStack resource. // +optional Resource *{{ .Name }}ResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` {{- if .StatusExtraType }} {{ .StatusExtraType }} `json:",inline"` @@ -140,7 +164,9 @@ func (i *{{ .Name }}) GetConditions() []metav1.Condition { // +kubebuilder:object:root=true // +kubebuilder:resource:categories=openstack // +kubebuilder:subresource:status +{{- if not .NoResourceID }} // +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +{{- end }} // +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" {{- range .AdditionalPrintColumns }} // +kubebuilder:printcolumn:name="{{ .Name }}",type="{{ .Type }}",JSONPath="{{ .JSONPath }}",description="{{ .Description }}" @@ -156,8 +182,8 @@ type {{ .Name }} struct { metav1.ObjectMeta `json:"metadata,omitempty"` // spec specifies the desired state of the resource. - // +optional - Spec {{ .Name }}Spec `json:"spec,omitempty"` + // +required + Spec {{ .Name }}Spec `json:"spec,omitzero"` // status defines the observed state of the resource. // +optional diff --git a/cmd/resource-generator/data/controller.template b/cmd/resource-generator/data/controller.template index 3879f901e..6a57c273d 100644 --- a/cmd/resource-generator/data/controller.template +++ b/cmd/resource-generator/data/controller.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/resource-generator/data/internal-osclients-mock-doc.go.template b/cmd/resource-generator/data/internal-osclients-mock-doc.go.template index 7ff63572c..ba9cfca3e 100644 --- a/cmd/resource-generator/data/internal-osclients-mock-doc.go.template +++ b/cmd/resource-generator/data/internal-osclients-mock-doc.go.template @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/resource-generator/main.go b/cmd/resource-generator/main.go index 6848b155f..c5d6bc042 100644 --- a/cmd/resource-generator/main.go +++ b/cmd/resource-generator/main.go @@ -12,7 +12,6 @@ import ( ) const ( - defaultYear = "2025" defaultAPIVersion = "v1alpha1" ) @@ -54,7 +53,6 @@ type additionalPrintColumn struct { type templateFields struct { APIVersion string - Year string Name string NameLower string IsNotNamed bool @@ -69,6 +67,10 @@ type templateFields struct { // When true, the UUID validation will be omitted from the Import.ID field. // Default is false (uses UUID). UsesNameAsID bool + // NoResourceID indicates this is a relationship resource without an + // OpenStack-assigned ID. When true, the generator omits import.id, + // status.ID, and the ID print column from the generated API types. + NoResourceID bool } var resources []templateFields = []templateFields{ @@ -126,6 +128,11 @@ var resources []templateFields = []templateFields{ { Name: "Role", }, + { + Name: "RoleAssignment", + IsNotNamed: true, + NoResourceID: true, + }, { Name: "Router", ExistingOSClient: true, @@ -146,6 +153,13 @@ var resources []templateFields = []templateFields{ Name: "Subnet", ExistingOSClient: true, }, + { + Name: "Trunk", + ExistingOSClient: true, + }, + { + Name: "User", + }, { Name: "Volume", }, @@ -155,6 +169,9 @@ var resources []templateFields = []templateFields{ { Name: "Service", }, + { + Name: "ShareNetwork", + }, { Name: "KeyPair", UsesNameAsID: true, // Keypairs uses name as ID, not UUID @@ -162,6 +179,16 @@ var resources []templateFields = []templateFields{ { Name: "Group", }, + { + Name: "Endpoint", + IsNotNamed: true, + }, + { + Name: "AddressScope", + }, + { + Name: "ApplicationCredential", + }, } // These resources won't be generated @@ -248,10 +275,6 @@ func addDefaults(resources []templateFields) { for i := range resources { resource := &resources[i] - if resource.Year == "" { - resource.Year = defaultYear - } - if resource.APIVersion == "" { resource.APIVersion = defaultAPIVersion } diff --git a/cmd/scaffold-controller/data/api/types.go.template b/cmd/scaffold-controller/data/api/types.go.template index b2cd8ee11..3d3c389b9 100644 --- a/cmd/scaffold-controller/data/api/types.go.template +++ b/cmd/scaffold-controller/data/api/types.go.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/scaffold-controller/data/apivalidation/apivalidation_test.go.template b/cmd/scaffold-controller/data/apivalidation/apivalidation_test.go.template new file mode 100644 index 000000000..7e565b450 --- /dev/null +++ b/cmd/scaffold-controller/data/apivalidation/apivalidation_test.go.template @@ -0,0 +1,136 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( +{{- if .AllCreateDependencies }} + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +{{- else }} + . "github.com/onsi/ginkgo/v2" +{{- end }} + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + {{ .PackageName }}Name = "{{ .PackageName }}" + {{ .PackageName }}ID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae120" +) + +func {{ .PackageName }}Stub(namespace *corev1.Namespace) *orcv1alpha1.{{ .Kind }} { + obj := &orcv1alpha1.{{ .Kind }}{} + obj.Name = {{ .PackageName }}Name + obj.Namespace = namespace.Name + return obj +} + +func test{{ .Kind }}Resource() *applyconfigv1alpha1.{{ .Kind }}ResourceSpecApplyConfiguration { + return applyconfigv1alpha1.{{ .Kind }}ResourceSpec(){{ range .RequiredCreateDependencies }}. + With{{ . }}Ref("{{ . | lower }}"){{ end }} +} + +func base{{ .Kind }}Patch(obj client.Object) *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration { + return applyconfigv1alpha1.{{ .Kind }}(obj.GetName(), obj.GetNamespace()). + WithSpec(applyconfigv1alpha1.{{ .Kind }}Spec(). + WithCloudCredentialsRef(testCredentials())) +} + +func test{{ .Kind }}Import() *applyconfigv1alpha1.{{ .Kind }}ImportApplyConfiguration { + return applyconfigv1alpha1.{{ .Kind }}Import().WithID({{ .PackageName }}ID) +} + +var _ = Describe("ORC {{ .Kind }} API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return {{ .PackageName }}Stub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration { + return base{{ .Kind }}Patch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithResource(test{{ .Kind }}Resource()) + }, + applyImport: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithImport(test{{ .Kind }}Import()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.{{ .Kind }}Import()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.{{ .Kind }}Import().WithFilter(applyconfigv1alpha1.{{ .Kind }}Filter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.{{ .Kind }}Import().WithFilter(applyconfigv1alpha1.{{ .Kind }}Filter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.{{ .Kind }}ApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.{{ .Kind }}).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.{{ .Kind }}).Spec.ManagedOptions.OnDelete + }, + }) +{{- if .RequiredCreateDependencies }} + + It("should reject a {{ .PackageName }} without required fields", func(ctx context.Context) { + obj := {{ .PackageName }}Stub(namespace) + patch := base{{ .Kind }}Patch(obj) + patch.Spec.WithResource(applyconfigv1alpha1.{{ .Kind }}ResourceSpec()) + Expect(applyObj(ctx, obj, patch)).NotTo(Succeed()) + }) +{{- end }} +{{- range .AllCreateDependencies }} + + It("should have immutable {{ . | camelCase }}Ref", func(ctx context.Context) { + obj := {{ $.PackageName }}Stub(namespace) + patch := base{{ $.Kind }}Patch(obj) + patch.Spec.WithResource(test{{ $.Kind }}Resource(). + With{{ . }}Ref("{{ . | lower }}-a")) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + + patch.Spec.WithResource(test{{ $.Kind }}Resource(). + With{{ . }}Ref("{{ . | lower }}-b")) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("{{ . | camelCase }}Ref is immutable"))) + }) +{{- end }} + + // TODO(scaffolding): Add more resource-specific validation tests. + // Some common things to test: + // - Immutability of fields with `self == oldSelf` validation + // - Enum validation (valid and invalid values) + // - Numeric range validation (min/max bounds) + // - Tag uniqueness (if the resource has tags with listType=set) + // - Format validation (CIDR, UUID, etc.) + // - Cross-field validation rules +}) diff --git a/cmd/scaffold-controller/data/client/client.go.template b/cmd/scaffold-controller/data/client/client.go.template index c0bebee4d..bba2af076 100644 --- a/cmd/scaffold-controller/data/client/client.go.template +++ b/cmd/scaffold-controller/data/client/client.go.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/scaffold-controller/data/controller/actuator.go.template b/cmd/scaffold-controller/data/controller/actuator.go.template index dc083e79d..1eca3abf3 100644 --- a/cmd/scaffold-controller/data/controller/actuator.go.template +++ b/cmd/scaffold-controller/data/controller/actuator.go.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,9 +25,6 @@ import ( "{{ .GophercloudModule }}" corev1 "k8s.io/api/core/v1" -{{- if len .ImportDependencies }} - apierrors "k8s.io/apimachinery/pkg/api/errors" -{{- end }} "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -37,6 +34,9 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" +{{- if len .ImportDependencies }} + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" +{{- end }} orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" ) @@ -106,24 +106,12 @@ func (actuator {{ .PackageName }}Actuator) ListOSResourcesForImport(ctx context. var reconcileStatus progress.ReconcileStatus {{- range .ImportDependencies }} {{ $depNameCamelCase := . | camelCase }} - {{ $depNameCamelCase }} := &orcv1alpha1.{{ . }}{} - if filter.{{ . }}Ref != nil { - {{ $depNameCamelCase }}Key := client.ObjectKey{Name: string(*filter.{{ . }}Ref), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, {{ $depNameCamelCase }}Key, {{ $depNameCamelCase }}); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("{{ . }}", {{ $depNameCamelCase }}Key.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching {{ $depNameCamelCase }} %s: %w", {{ $depNameCamelCase }}Key.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable({{ $depNameCamelCase }}) || {{ $depNameCamelCase }}.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("{{ . }}", {{ $depNameCamelCase }}Key.Name, progress.WaitingOnReady)) - } - } - } + {{ $depNameCamelCase }}, rs := dependency.FetchDependency[*orcv1alpha1.{{ . }}]( + ctx, actuator.k8sClient, obj.Namespace, + filter.{{ . }}Ref, "{{ . }}", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) {{- end }} if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { @@ -135,12 +123,12 @@ func (actuator {{ .PackageName }}Actuator) ListOSResourcesForImport(ctx context. Name: string(ptr.Deref(filter.Name, "")), Description: string(ptr.Deref(filter.Description, "")), {{- range .ImportDependencies }} - {{ . }}: ptr.Deref({{ . | camelCase }}.Status.ID, ""), + {{ . }}ID: ptr.Deref({{ . | camelCase }}.Status.ID, ""), {{- end }} // TODO(scaffolding): Add more import filters } - return actuator.osClient.List{{ .Kind }}s(ctx, listOpts), nil + return actuator.osClient.List{{ .Kind }}s(ctx, listOpts), {{ if len .ImportDependencies }}reconcileStatus{{ else }}nil{{ end }} } func (actuator {{ .PackageName }}Actuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { @@ -157,15 +145,13 @@ func (actuator {{ .PackageName }}Actuator) CreateResource(ctx context.Context, o {{- range .RequiredCreateDependencies }} {{ $depNameCamelCase := . | camelCase }} var {{ $depNameCamelCase }}ID string - {{ $depNameCamelCase }}, {{ $depNameCamelCase }}DepRS := {{ $depNameCamelCase }}Dependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.{{ . }}) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, - ) - reconcileStatus = reconcileStatus.WithReconcileStatus({{ $depNameCamelCase }}DepRS) - if {{ $depNameCamelCase }} != nil { - {{ $depNameCamelCase }}ID = ptr.Deref({{ $depNameCamelCase }}.Status.ID, "") - } + {{ $depNameCamelCase }}, {{ $depNameCamelCase }}DepRS := {{ $depNameCamelCase }}Dependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus({{ $depNameCamelCase }}DepRS) + if {{ $depNameCamelCase }} != nil { + {{ $depNameCamelCase }}ID = ptr.Deref({{ $depNameCamelCase }}.Status.ID, "") + } {{- end }} {{- range .OptionalCreateDependencies }} @@ -173,9 +159,7 @@ func (actuator {{ .PackageName }}Actuator) CreateResource(ctx context.Context, o var {{ $depNameCamelCase }}ID string if resource.{{ . }}Ref != nil { {{ $depNameCamelCase }}, {{ $depNameCamelCase }}DepRS := {{ $depNameCamelCase }}Dependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.{{ . }}) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus({{ $depNameCamelCase }}DepRS) if {{ $depNameCamelCase }} != nil { @@ -200,7 +184,6 @@ func (actuator {{ .PackageName }}Actuator) CreateResource(ctx context.Context, o osResource, err := actuator.osClient.Create{{ .Kind }}(ctx, createOpts) if err != nil { - // We should require the spec to be updated before retrying a create which returned a conflict if !orcerrors.IsRetryable(err) { err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) } @@ -248,12 +231,10 @@ func (actuator {{ .PackageName }}Actuator) updateResource(ctx context.Context, o _, err = actuator.osClient.Update{{ .Kind }}(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/cmd/scaffold-controller/data/controller/actuator_test.go.template b/cmd/scaffold-controller/data/controller/actuator_test.go.template index 2926ee701..59d7e9c31 100644 --- a/cmd/scaffold-controller/data/controller/actuator_test.go.template +++ b/cmd/scaffold-controller/data/controller/actuator_test.go.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/scaffold-controller/data/controller/controller.go.template b/cmd/scaffold-controller/data/controller/controller.go.template index 98d57af78..798ba52f5 100644 --- a/cmd/scaffold-controller/data/controller/controller.go.template +++ b/cmd/scaffold-controller/data/controller/controller.go.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package {{ .PackageName }} import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" {{- if or (len .AllCreateDependencies) (len .ImportDependencies) }} @@ -44,17 +45,22 @@ const controllerName = "{{ .PackageName }}" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources={{ .PackageName }}s/status,verbs=get;update;patch type {{ .PackageName }}ReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return {{ .PackageName }}ReconcilerConstructor{scopeFactory: scopeFactory} + return &{{ .PackageName }}ReconcilerConstructor{scopeFactory: scopeFactory} } func ({{ .PackageName }}ReconcilerConstructor) GetName() string { return controllerName } +func (c *{{ .PackageName }}ReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + {{- $kind := .Kind }} {{- $packageName := .PackageName }} {{- range .RequiredCreateDependencies }} @@ -100,7 +106,7 @@ var {{ $depNameCamelCase }}ImportDependency = dependency.NewDependency[*orcv1alp {{- end }} // SetupWithManager sets up the controller with the Manager. -func (c {{ .PackageName }}ReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *{{ .PackageName }}ReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) {{- if or (len .AllCreateDependencies) (len .ImportDependencies) }} k8sClient := mgr.GetClient() @@ -148,6 +154,6 @@ func (c {{ .PackageName }}ReconcilerConstructor) SetupWithManager(ctx context.Co return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, {{ .PackageName }}HelperFactory{}, {{ .PackageName }}StatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, {{ .PackageName }}HelperFactory{}, {{ .PackageName }}StatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/cmd/scaffold-controller/data/controller/status.go.template b/cmd/scaffold-controller/data/controller/status.go.template index ed9890263..98bc23b94 100644 --- a/cmd/scaffold-controller/data/controller/status.go.template +++ b/cmd/scaffold-controller/data/controller/status.go.template @@ -1,5 +1,5 @@ /* -Copyright {{ .Year }} The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cmd/scaffold-controller/data/tests/create-full/00-create-resource.yaml.template b/cmd/scaffold-controller/data/tests/create-full/00-create-resource.yaml.template index 3598d91c5..06124a45b 100644 --- a/cmd/scaffold-controller/data/tests/create-full/00-create-resource.yaml.template +++ b/cmd/scaffold-controller/data/tests/create-full/00-create-resource.yaml.template @@ -7,7 +7,7 @@ metadata: name: {{ $packageName }}-create-full spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -21,7 +21,7 @@ metadata: name: {{ .PackageName }}-create-full spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed diff --git a/cmd/scaffold-controller/data/tests/create-minimal/00-create-resource.yaml.template b/cmd/scaffold-controller/data/tests/create-minimal/00-create-resource.yaml.template index 505a48883..abb027cc0 100644 --- a/cmd/scaffold-controller/data/tests/create-minimal/00-create-resource.yaml.template +++ b/cmd/scaffold-controller/data/tests/create-minimal/00-create-resource.yaml.template @@ -7,7 +7,7 @@ metadata: name: {{ $packageName }}-create-minimal spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -21,7 +21,7 @@ metadata: name: {{ .PackageName }}-create-minimal spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -30,7 +30,7 @@ spec: {{- if len .RequiredCreateDependencies }} resource: {{- range .RequiredCreateDependencies }} - {{ . | camelCase }}Ref: {{ $packageName }}-create-full + {{ . | camelCase }}Ref: {{ $packageName }}-create-minimal {{- end }} {{- else }} resource: {} diff --git a/cmd/scaffold-controller/data/tests/dependency/00-create-resources-missing-deps.yaml.template b/cmd/scaffold-controller/data/tests/dependency/00-create-resources-missing-deps.yaml.template index b07a4666c..d58086401 100644 --- a/cmd/scaffold-controller/data/tests/dependency/00-create-resources-missing-deps.yaml.template +++ b/cmd/scaffold-controller/data/tests/dependency/00-create-resources-missing-deps.yaml.template @@ -9,7 +9,7 @@ metadata: name: {{ $packageName }}-dependency spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -25,7 +25,7 @@ metadata: name: {{ $packageName }}-dependency-no-{{ . | lower }} spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -37,9 +37,9 @@ spec: {{ . | camelCase }}Ref: {{ $packageName }}-dependency {{- end }} # TODO(scaffolding): Add the necessary fields to create the resource -{{- end }} -{{- end }} -{{- range .OptionalCreateDependencies }} +{{ end -}} +{{ end -}} +{{ range .OptionalCreateDependencies -}} --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: {{ $kind }} @@ -47,7 +47,7 @@ metadata: name: {{ $packageName }}-dependency-no-{{ . | lower }} spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -65,7 +65,7 @@ metadata: name: {{ .PackageName }}-dependency-no-secret spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: {{ .PackageName }}-dependency managementPolicy: managed diff --git a/cmd/scaffold-controller/data/tests/dependency/01-create-dependencies.yaml.template b/cmd/scaffold-controller/data/tests/dependency/01-create-dependencies.yaml.template index abf7f84a6..aa706cf07 100644 --- a/cmd/scaffold-controller/data/tests/dependency/01-create-dependencies.yaml.template +++ b/cmd/scaffold-controller/data/tests/dependency/01-create-dependencies.yaml.template @@ -14,7 +14,7 @@ metadata: name: {{ $packageName }}-dependency-pending spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -29,7 +29,7 @@ metadata: name: {{ $packageName }}-dependency spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed diff --git a/cmd/scaffold-controller/data/tests/dependency/02-delete-dependencies.yaml.template b/cmd/scaffold-controller/data/tests/dependency/02-delete-dependencies.yaml.template index 6afc372ef..a5e38546d 100644 --- a/cmd/scaffold-controller/data/tests/dependency/02-delete-dependencies.yaml.template +++ b/cmd/scaffold-controller/data/tests/dependency/02-delete-dependencies.yaml.template @@ -5,7 +5,7 @@ kind: TestStep commands: # We expect the deletion to hang due to the finalizer, so use --wait=false {{- range .AllCreateDependencies }} - - command: kubectl delete {{ . | lower }} {{ $packageName }}-dependency --wait=false + - command: kubectl delete {{ . | lower }}.openstack.k-orc.cloud {{ $packageName }}-dependency --wait=false namespaced: true {{- end }} - command: kubectl delete secret {{ $packageName }}-dependency --wait=false diff --git a/cmd/scaffold-controller/data/tests/dependency/03-assert.yaml.template b/cmd/scaffold-controller/data/tests/dependency/03-assert.yaml.template index fa188a9d1..aa96bb1aa 100644 --- a/cmd/scaffold-controller/data/tests/dependency/03-assert.yaml.template +++ b/cmd/scaffold-controller/data/tests/dependency/03-assert.yaml.template @@ -5,7 +5,7 @@ kind: TestAssert commands: # Dependencies that were prevented deletion before should now be gone {{- range .AllCreateDependencies }} -- script: "! kubectl get {{ . | lower }} {{ $packageName }}-dependency --namespace $NAMESPACE" +- script: "! kubectl get {{ . | lower }}.openstack.k-orc.cloud {{ $packageName }}-dependency --namespace $NAMESPACE" skipLogOutput: true {{- end }} - script: "! kubectl get secret {{ $packageName }}-dependency --namespace $NAMESPACE" diff --git a/cmd/scaffold-controller/data/tests/import-dependency/01-create-trap-resource.yaml.template b/cmd/scaffold-controller/data/tests/import-dependency/01-create-trap-resource.yaml.template index 4c6662c37..6414ec52f 100644 --- a/cmd/scaffold-controller/data/tests/import-dependency/01-create-trap-resource.yaml.template +++ b/cmd/scaffold-controller/data/tests/import-dependency/01-create-trap-resource.yaml.template @@ -7,22 +7,7 @@ metadata: name: {{ $packageName }}-import-dependency-not-this-one spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created - cloudName: openstack - secretName: openstack-clouds - managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} -{{ end -}} -{{ range .RequiredCreateDependencies -}} ---- -apiVersion: openstack.k-orc.cloud/v1alpha1 -kind: {{ . }} -metadata: - name: {{ $packageName }}-import-dependency-not-this-one -spec: - cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -37,14 +22,11 @@ metadata: name: {{ $packageName }}-import-dependency-not-this-one spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed resource: -{{- range .RequiredCreateDependencies }} - {{ . | camelCase }}Ref: {{ $packageName }}-import-dependency-not-this-one -{{- end }} {{- range .ImportDependencies }} {{ . | camelCase }}Ref: {{ $packageName }}-import-dependency-not-this-one {{- end }} diff --git a/cmd/scaffold-controller/data/tests/import-dependency/02-create-resource.yaml.template b/cmd/scaffold-controller/data/tests/import-dependency/02-create-resource.yaml.template index 206089c0b..763b8e3de 100644 --- a/cmd/scaffold-controller/data/tests/import-dependency/02-create-resource.yaml.template +++ b/cmd/scaffold-controller/data/tests/import-dependency/02-create-resource.yaml.template @@ -1,19 +1,4 @@ {{ $packageName := .PackageName -}} -{{ range .RequiredCreateDependencies -}} ---- -apiVersion: openstack.k-orc.cloud/v1alpha1 -kind: {{ . }} -metadata: - name: {{ $packageName }}-import-dependency-external -spec: - cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created - cloudName: openstack - secretName: openstack-clouds - managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} -{{ end -}} {{ range .ImportDependencies -}} --- apiVersion: openstack.k-orc.cloud/v1alpha1 @@ -22,7 +7,7 @@ metadata: name: {{ $packageName }}-import-dependency-external spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -36,14 +21,11 @@ metadata: name: {{ $packageName }}-import-dependency-external spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created - cloudName: openstack-admin + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack secretName: openstack-clouds managementPolicy: managed resource: -{{- range .RequiredCreateDependencies }} - {{ . | camelCase }}Ref: {{ $packageName }}-import-dependency-external -{{- end }} {{- range .ImportDependencies }} {{ . | camelCase }}Ref: {{ $packageName }}-import-dependency-external {{- end }} diff --git a/cmd/scaffold-controller/data/tests/import-dependency/03-assert.yaml.template b/cmd/scaffold-controller/data/tests/import-dependency/03-assert.yaml.template index c4c2e4879..0f1e4487a 100644 --- a/cmd/scaffold-controller/data/tests/import-dependency/03-assert.yaml.template +++ b/cmd/scaffold-controller/data/tests/import-dependency/03-assert.yaml.template @@ -4,6 +4,6 @@ apiVersion: kuttl.dev/v1beta1 kind: TestAssert commands: {{- range .ImportDependencies }} -- script: "! kubectl get {{ . | lower }} {{ $packageName }}-import-dependency --namespace $NAMESPACE" +- script: "! kubectl get {{ . | lower }}.openstack.k-orc.cloud {{ $packageName }}-import-dependency --namespace $NAMESPACE" skipLogOutput: true {{- end }} diff --git a/cmd/scaffold-controller/data/tests/import-dependency/03-delete-import-dependencies.yaml.template b/cmd/scaffold-controller/data/tests/import-dependency/03-delete-import-dependencies.yaml.template index 45c3d2658..184f2f866 100644 --- a/cmd/scaffold-controller/data/tests/import-dependency/03-delete-import-dependencies.yaml.template +++ b/cmd/scaffold-controller/data/tests/import-dependency/03-delete-import-dependencies.yaml.template @@ -5,6 +5,6 @@ kind: TestStep commands: # We should be able to delete the import dependencies {{- range .ImportDependencies }} - - command: kubectl delete {{ . | lower }} {{ $packageName }}-import-dependency + - command: kubectl delete {{ . | lower }}.openstack.k-orc.cloud {{ $packageName }}-import-dependency namespaced: true {{- end }} diff --git a/cmd/scaffold-controller/data/tests/import-dependency/04-assert.yaml.template b/cmd/scaffold-controller/data/tests/import-dependency/04-assert.yaml.template index e7f733ae9..cab39b2e5 100644 --- a/cmd/scaffold-controller/data/tests/import-dependency/04-assert.yaml.template +++ b/cmd/scaffold-controller/data/tests/import-dependency/04-assert.yaml.template @@ -2,5 +2,5 @@ apiVersion: kuttl.dev/v1beta1 kind: TestAssert commands: -- script: "! kubectl get {{ .PackageName }} {{ .PackageName }}-import-dependency --namespace $NAMESPACE" +- script: "! kubectl get {{ .PackageName }}.openstack.k-orc.cloud {{ .PackageName }}-import-dependency --namespace $NAMESPACE" skipLogOutput: true diff --git a/cmd/scaffold-controller/data/tests/import-error/00-create-resources.yaml.template b/cmd/scaffold-controller/data/tests/import-error/00-create-resources.yaml.template index 8ff66bd03..79270d6b8 100644 --- a/cmd/scaffold-controller/data/tests/import-error/00-create-resources.yaml.template +++ b/cmd/scaffold-controller/data/tests/import-error/00-create-resources.yaml.template @@ -7,7 +7,7 @@ metadata: name: {{ $packageName }}-import-error spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -21,7 +21,7 @@ metadata: name: {{ .PackageName }}-import-error-external-1 spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -38,7 +38,7 @@ metadata: name: {{ .PackageName }}-import-error-external-2 spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed diff --git a/cmd/scaffold-controller/data/tests/import/01-create-trap-resource.yaml.template b/cmd/scaffold-controller/data/tests/import/01-create-trap-resource.yaml.template index 4ab6adb51..86cfc4319 100644 --- a/cmd/scaffold-controller/data/tests/import/01-create-trap-resource.yaml.template +++ b/cmd/scaffold-controller/data/tests/import/01-create-trap-resource.yaml.template @@ -7,7 +7,7 @@ metadata: name: {{ $packageName }}-import-external-not-this-one spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -24,7 +24,7 @@ metadata: name: {{ .PackageName }}-import-external-not-this-one spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed diff --git a/cmd/scaffold-controller/data/tests/import/02-create-resource.yaml.template b/cmd/scaffold-controller/data/tests/import/02-create-resource.yaml.template index 1b21ced42..7f6d07bc1 100644 --- a/cmd/scaffold-controller/data/tests/import/02-create-resource.yaml.template +++ b/cmd/scaffold-controller/data/tests/import/02-create-resource.yaml.template @@ -7,7 +7,7 @@ metadata: name: {{ $packageName }}-import spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -21,7 +21,7 @@ metadata: name: {{ .PackageName }}-import-external spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed diff --git a/cmd/scaffold-controller/data/tests/update/00-minimal-resource.yaml.template b/cmd/scaffold-controller/data/tests/update/00-minimal-resource.yaml.template index d1c77fd50..28468b95d 100644 --- a/cmd/scaffold-controller/data/tests/update/00-minimal-resource.yaml.template +++ b/cmd/scaffold-controller/data/tests/update/00-minimal-resource.yaml.template @@ -7,7 +7,7 @@ metadata: name: {{ $packageName }}-update spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created cloudName: openstack secretName: openstack-clouds managementPolicy: managed @@ -21,7 +21,7 @@ metadata: name: {{ .PackageName }}-update spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created or updated + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created or updated cloudName: openstack secretName: openstack-clouds managementPolicy: managed diff --git a/cmd/scaffold-controller/data/tests/update/00-prerequisites.yaml.template b/cmd/scaffold-controller/data/tests/update/00-secret.yaml.template similarity index 100% rename from cmd/scaffold-controller/data/tests/update/00-prerequisites.yaml.template rename to cmd/scaffold-controller/data/tests/update/00-secret.yaml.template diff --git a/cmd/scaffold-controller/main.go b/cmd/scaffold-controller/main.go index 37ac50c75..e26dfe300 100644 --- a/cmd/scaffold-controller/main.go +++ b/cmd/scaffold-controller/main.go @@ -13,7 +13,6 @@ import ( "regexp" "slices" "strings" - "time" "golang.org/x/text/cases" "golang.org/x/text/language" @@ -32,7 +31,6 @@ type templateFields struct { OpenStackJSONObject string AvailablePollingPeriod int DeletingPollingPeriod int - Year int RequiredCreateDependencies strList OptionalCreateDependencies strList AllCreateDependencies strList @@ -180,7 +178,6 @@ func main() { fields.PackageName = strings.ToLower(fields.Kind) fields.GophercloudPackage = path.Base(fields.GophercloudModule) - fields.Year = time.Now().Year() fields.AllCreateDependencies = slices.Concat(fields.RequiredCreateDependencies, fields.OptionalCreateDependencies) render("data/api", filepath.Join("api", "v1alpha1"), &fields) @@ -188,6 +185,7 @@ func main() { render("data/controller", filepath.Join("internal", "controllers", fields.PackageName), &fields) render("data/tests", filepath.Join("internal", "controllers", fields.PackageName, "tests"), &fields) render("data/samples", filepath.Join("config", "samples"), &fields) + render("data/apivalidation", filepath.Join("test", "apivalidations"), &fields) } func render(srcDir, distDir string, resource *templateFields) { @@ -205,7 +203,7 @@ func render(srcDir, distDir string, resource *templateFields) { for _, file := range files { if file.IsDir() { - if file.Name() == "dependency" && len(resource.OptionalCreateDependencies) == 0 { + if file.Name() == "dependency" && len(resource.AllCreateDependencies) == 0 { continue } if file.Name() == "import-dependency" && len(resource.ImportDependencies) == 0 { @@ -234,6 +232,8 @@ func render(srcDir, distDir string, resource *templateFields) { tplName = resource.PackageName + ".go" case "sample.yaml": tplName = "openstack_v1alpha1_" + resource.PackageName + ".yaml" + case "apivalidation_test.go": + tplName = resource.PackageName + "_test.go" } var funcMap = template.FuncMap{ diff --git a/config/crd/bases/openstack.k-orc.cloud_addressscopes.yaml b/config/crd/bases/openstack.k-orc.cloud_addressscopes.yaml new file mode 100644 index 000000000..1416386f3 --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_addressscopes.yaml @@ -0,0 +1,354 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: addressscopes.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: AddressScope + listKind: AddressScopeList + plural: addressscopes + singular: addressscope + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: AddressScope is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + ipVersion: + description: ipVersion is the IP protocol version. + enum: + - 4 + - 6 + format: int32 + type: integer + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + projectRef: + description: projectRef is a reference to the ORC Project + which this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + shared: + description: |- + shared indicates whether this resource is shared across all + projects or not. By default, only admin users can change set + this value. + type: boolean + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + ipVersion: + description: ipVersion is the IP protocol version. + enum: + - 4 + - 6 + format: int32 + type: integer + x-kubernetes-validations: + - message: ipVersion is immutable + rule: self == oldSelf + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + projectRef: + description: projectRef is a reference to the ORC Project which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: projectRef is immutable + rule: self == oldSelf + shared: + description: |- + shared indicates whether this resource is shared across all + projects or not. By default, only admin users can change set + this value. We can't unshared a shared address scope; Neutron + enforces this. + type: boolean + x-kubernetes-validations: + - message: shared address scope can't be unshared + rule: '!(oldSelf && !self)' + required: + - ipVersion + type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + ipVersion: + description: ipVersion is the IP protocol version. + format: int32 + type: integer + name: + description: name is a Human-readable name for the resource. Might + not be unique. + maxLength: 1024 + type: string + projectID: + description: projectID is the ID of the Project to which the resource + is associated. + maxLength: 1024 + type: string + shared: + description: |- + shared indicates whether this resource is shared across all + projects or not. By default, only admin users can change set + this value. + type: boolean + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/openstack.k-orc.cloud_applicationcredentials.yaml b/config/crd/bases/openstack.k-orc.cloud_applicationcredentials.yaml new file mode 100644 index 000000000..34414c26c --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_applicationcredentials.yaml @@ -0,0 +1,456 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: applicationcredentials.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: ApplicationCredential + listKind: ApplicationCredentialList + plural: applicationcredentials + singular: applicationcredential + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ApplicationCredential is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 2 + properties: + description: + description: description of the existing resource + maxLength: 1024 + type: string + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + userRef: + description: |- + userRef is a reference to the ORC User which this resource is associated with. + Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. + maxLength: 253 + minLength: 1 + type: string + required: + - userRef + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + accessRules: + description: accessRules is a list of fine grained access control + rules + items: + description: ApplicationCredentialAccessRule defines an access + rule + minProperties: 1 + properties: + method: + description: method that the application credential is permitted + to use for a given API endpoint + enum: + - CONNECT + - DELETE + - GET + - HEAD + - OPTIONS + - PATCH + - POST + - PUT + - TRACE + type: string + path: + description: path that the application credential is permitted + to access + maxLength: 1024 + type: string + serviceRef: + description: serviceRef identifier for the service that + the application credential is permitted to access + maxLength: 253 + minLength: 1 + type: string + type: object + maxItems: 256 + type: array + x-kubernetes-list-type: atomic + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + expiresAt: + description: expiresAt is the time of expiration for the application + credential. If unset, the application credential does not expire. + format: date-time + type: string + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + roleRefs: + description: roleRefs may only contain roles that the user has + assigned on the project. If not provided, the roles assigned + to the application credential will be the same as the roles + in the current token. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 256 + type: array + x-kubernetes-list-type: atomic + secretRef: + description: secretRef is a reference to a Secret containing the + application credential secret + maxLength: 253 + minLength: 1 + type: string + unrestricted: + description: unrestricted is a flag indicating whether the application + credential may be used for creation or destruction of other + application credentials or trusts + type: boolean + userRef: + description: |- + userRef is a reference to the ORC User which this resource is associated with. + Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. + maxLength: 253 + minLength: 1 + type: string + required: + - secretRef + - userRef + type: object + x-kubernetes-validations: + - message: ApplicationCredentialResourceSpec is immutable + rule: self == oldSelf + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + accessRules: + description: accessRules is a list of fine grained access control + rules + items: + properties: + id: + description: id is the ID of this access rule + maxLength: 1024 + type: string + method: + description: method that the application credential is permitted + to use for a given API endpoint + maxLength: 32 + type: string + path: + description: path that the application credential is permitted + to access + maxLength: 1024 + type: string + service: + description: service type identifier for the service that + the application credential is permitted to access + maxLength: 1024 + type: string + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + expiresAt: + description: expiresAt is the time of expiration for the application + credential. If unset, the application credential does not expire. + format: date-time + type: string + name: + description: name is a Human-readable name for the resource. Might + not be unique. + maxLength: 1024 + type: string + projectID: + description: projectID of the project the application credential + was created for and that authentication requests using this + application credential will be scoped to. + maxLength: 1024 + type: string + roles: + description: roles is a list of role objects may only contain + roles that the user has assigned on the project + items: + properties: + domainID: + description: domainID of the domain of this role + maxLength: 1024 + type: string + id: + description: id is the ID of a role + maxLength: 1024 + type: string + name: + description: name of an existing role + maxLength: 1024 + type: string + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + unrestricted: + description: unrestricted is a flag indicating whether the application + credential may be used for creation or destruction of other + application credentials or trusts + type: boolean + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/openstack.k-orc.cloud_domains.yaml b/config/crd/bases/openstack.k-orc.cloud_domains.yaml index 893ff831c..7f74e8a68 100644 --- a/config/crd/bases/openstack.k-orc.cloud_domains.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_domains.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: domains.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -108,6 +108,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -167,6 +168,14 @@ spec: minLength: 1 type: string type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -264,6 +273,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -286,6 +304,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_endpoints.yaml b/config/crd/bases/openstack.k-orc.cloud_endpoints.yaml new file mode 100644 index 000000000..8f753813f --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_endpoints.yaml @@ -0,0 +1,347 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: endpoints.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: Endpoint + listKind: EndpointList + plural: endpoints + singular: endpoint + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Endpoint is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + interface: + description: interface of the existing endpoint. + enum: + - admin + - internal + - public + type: string + serviceRef: + description: serviceRef is a reference to the ORC Service + which this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + url: + description: url is the URL of the existing endpoint. + maxLength: 1024 + type: string + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + x-kubernetes-validations: + - message: description is immutable + rule: self == oldSelf + enabled: + description: enabled indicates whether the endpoint is enabled + or not. + type: boolean + interface: + description: interface indicates the visibility of the endpoint. + enum: + - admin + - internal + - public + type: string + serviceRef: + description: serviceRef is a reference to the ORC Service which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: serviceRef is immutable + rule: self == oldSelf + url: + description: url is the endpoint URL. + maxLength: 1024 + type: string + required: + - interface + - serviceRef + - url + type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + enabled: + description: enabled indicates whether the endpoint is enabled + or not. + type: boolean + interface: + description: interface indicates the visibility of the endpoint. + maxLength: 128 + type: string + serviceID: + description: serviceID is the ID of the Service to which the resource + is associated. + maxLength: 1024 + type: string + url: + description: url is the endpoint URL. + maxLength: 1024 + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/openstack.k-orc.cloud_flavors.yaml b/config/crd/bases/openstack.k-orc.cloud_flavors.yaml index d1c930aa2..089c78ea6 100644 --- a/config/crd/bases/openstack.k-orc.cloud_flavors.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_flavors.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: flavors.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -120,6 +120,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -166,6 +167,9 @@ spec: maxLength: 65535 minLength: 1 type: string + x-kubernetes-validations: + - message: description is immutable + rule: self == oldSelf disk: description: |- disk is the size of the root disk that will be created in GiB. If 0 @@ -179,6 +183,9 @@ spec: format: int32 minimum: 0 type: integer + x-kubernetes-validations: + - message: disk is immutable + rule: self == oldSelf ephemeral: description: |- ephemeral is the size of the ephemeral disk that will be created, in GiB. @@ -188,10 +195,50 @@ spec: format: int32 minimum: 0 type: integer + x-kubernetes-validations: + - message: ephemeral is immutable + rule: self == oldSelf + extraSpecs: + description: extraSpecs is a list of key-value pairs that define + extra specifications for the flavor. + items: + properties: + name: + description: name is the name of the extraspec + maxLength: 255 + pattern: ^[a-zA-Z0-9-_:. ]+$ + type: string + value: + description: value is the value of the extraspec + maxLength: 255 + type: string + required: + - name + - value + type: object + maxItems: 128 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + id: + description: |- + id will be the id of the created resource. If not specified, a random + UUID will be generated by OpenStack. + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9._-]([a-zA-Z0-9. _-]*[a-zA-Z0-9._-])?$ + type: string + x-kubernetes-validations: + - message: id is immutable + rule: self == oldSelf isPublic: description: isPublic flags a flavor as being available to all projects or not. type: boolean + x-kubernetes-validations: + - message: isPublic is immutable + rule: self == oldSelf name: description: |- name will be the name of the created resource. If not specified, the @@ -200,11 +247,17 @@ spec: minLength: 1 pattern: ^[^,]+$ type: string + x-kubernetes-validations: + - message: name is immutable + rule: self == oldSelf ram: description: ram is the memory of the flavor, measured in MB. format: int32 minimum: 1 type: integer + x-kubernetes-validations: + - message: ram is immutable + rule: self == oldSelf swap: description: |- swap is the size of a dedicated swap disk that will be allocated, in @@ -212,19 +265,30 @@ spec: format: int32 minimum: 0 type: integer + x-kubernetes-validations: + - message: swap is immutable + rule: self == oldSelf vcpus: description: vcpus is the number of vcpus for the flavor. format: int32 minimum: 1 type: integer + x-kubernetes-validations: + - message: vcpus is immutable + rule: self == oldSelf required: - disk - ram - vcpus type: object - x-kubernetes-validations: - - message: FlavorResourceSpec is immutable - rule: self == oldSelf + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -322,6 +386,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -341,6 +414,23 @@ spec: description: ephemeral is the size of the ephemeral disk, in GiB. format: int32 type: integer + extraSpecs: + description: extraSpecs is a map of key-value pairs that define + extra specifications for the flavor. + items: + properties: + name: + description: name is the name of the extraspec + maxLength: 255 + type: string + value: + description: value is the value of the extraspec + maxLength: 255 + type: string + type: object + maxItems: 128 + type: array + x-kubernetes-list-type: atomic isPublic: description: isPublic flags a flavor as being available to all projects or not. @@ -366,6 +456,8 @@ spec: type: integer type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_floatingips.yaml b/config/crd/bases/openstack.k-orc.cloud_floatingips.yaml index 686b41c71..041faf837 100644 --- a/config/crd/bases/openstack.k-orc.cloud_floatingips.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_floatingips.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: floatingips.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -192,6 +192,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -312,6 +313,14 @@ spec: - message: Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' must be set rule: has(self.floatingNetworkRef) != has(self.floatingSubnetRef) + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -409,6 +418,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -479,6 +497,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_groups.yaml b/config/crd/bases/openstack.k-orc.cloud_groups.yaml index e62f33c1c..49e5ad809 100644 --- a/config/crd/bases/openstack.k-orc.cloud_groups.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_groups.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: groups.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -109,6 +109,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -172,6 +173,14 @@ spec: minLength: 1 type: string type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -269,6 +278,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -291,6 +309,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_images.yaml b/config/crd/bases/openstack.k-orc.cloud_images.yaml index 6b5dce9b9..ad3ebfe3e 100644 --- a/config/crd/bases/openstack.k-orc.cloud_images.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_images.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: images.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -122,6 +122,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -540,6 +541,14 @@ spec: - community type: string type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -644,6 +653,15 @@ spec: type: integer id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -713,6 +731,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_keypairs.yaml b/config/crd/bases/openstack.k-orc.cloud_keypairs.yaml index 969748e90..051ec07e8 100644 --- a/config/crd/bases/openstack.k-orc.cloud_keypairs.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_keypairs.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: keypairs.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -104,6 +104,7 @@ spec: the resource name as the unique identifier, not a UUID. When specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. + maxLength: 1024 type: string type: object managedOptions: @@ -168,6 +169,14 @@ spec: required: - publicKey type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -265,6 +274,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -289,6 +307,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_networks.yaml b/config/crd/bases/openstack.k-orc.cloud_networks.yaml index bba47e4c8..9d5fd6544 100644 --- a/config/crd/bases/openstack.k-orc.cloud_networks.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_networks.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: networks.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -178,6 +178,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -309,6 +310,14 @@ spec: type: array x-kubernetes-list-type: set type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -406,6 +415,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -540,6 +558,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_ports.yaml b/config/crd/bases/openstack.k-orc.cloud_ports.yaml index 64c66bbf5..6f822daff 100644 --- a/config/crd/bases/openstack.k-orc.cloud_ports.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_ports.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: ports.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -105,6 +105,10 @@ spec: maxLength: 255 minLength: 1 type: string + macAddress: + description: macAddress is the MAC address of the port. + maxLength: 32 + type: string name: description: name of the existing resource maxLength: 255 @@ -188,6 +192,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -294,6 +299,43 @@ spec: maxLength: 255 minLength: 1 type: string + hostID: + description: |- + hostID specifies the host where the port will be bound. + Note that when the port is attached to a server, OpenStack may + rebind the port to the server's actual compute host, which may + differ from the specified hostID if no matching scheduler hint + is used. In this case the port's status will reflect the actual + binding host, not the value specified here. + maxProperties: 1 + minProperties: 1 + properties: + id: + description: |- + id is the literal host ID string to use for binding:host_id. + This is mutually exclusive with serverRef. + maxLength: 36 + type: string + serverRef: + description: |- + serverRef is a reference to an ORC Server resource from which to + retrieve the hostID for port binding. The hostID will be read from + the Server's status.resource.hostID field. + This is mutually exclusive with id. + maxLength: 253 + minLength: 1 + type: string + type: object + x-kubernetes-validations: + - message: hostID is immutable + rule: self == oldSelf + - message: exactly one of id or serverRef must be set + rule: (has(self.id) && size(self.id) > 0) != (has(self.serverRef) + && size(self.serverRef) > 0) + macAddress: + description: macAddress is the MAC address of the port. + maxLength: 32 + type: string name: description: name is a human-readable name of the port. If not set, the object's name will be used. @@ -335,14 +377,24 @@ spec: x-kubernetes-validations: - message: projectRef is immutable rule: self == oldSelf + propagateUplinkStatus: + description: |- + propagateUplinkStatus represents the uplink status propagation of + the port. + The field is now immutable due to a limitation on + Dalmatian (2024.2) release, we should address this later. + https://github.com/k-orc/openstack-resource-controller/pull/641#discussion_r2694783787 + type: boolean + x-kubernetes-validations: + - message: propagateUplinkStatus is immutable + rule: self == oldSelf securityGroupRefs: description: |- - securityGroupRefs are the names of the security groups associated + securityGroupRefs are references to the security groups associated with this port. items: - maxLength: 255 + maxLength: 253 minLength: 1 - pattern: ^[^,]+$ type: string maxItems: 64 type: array @@ -360,6 +412,47 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: set + trustedVIF: + description: |- + trustedVIF indicates whether the VF for the port will become + trusted by physical function to perform some privileged + operations. Only admin users can create ports with this field. + type: boolean + valueSpecs: + description: |- + valueSpecs are extra parameters to include in the API request + with OpenStack. This is an extension point for the API, so what + they do and if they are supported, depends on the specific + OpenStack implementation. This was meant to work similar to the + property on Heat port resource. Since this depends on the + underlying implementation, we can't predict its fields, and + therefore, we don't know how to reconcile them in advance. Use + this field wisely and be aware of the expected behavior. + items: + properties: + key: + description: key is the name of the Neutron API extension + parameter. + maxLength: 255 + minLength: 1 + type: string + value: + description: value is the value of the Neutron API extension + parameter. + maxLength: 255 + type: string + required: + - key + - value + type: object + maxItems: 128 + type: array + x-kubernetes-list-map-keys: + - key + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: valueSpecs is immutable + rule: self == oldSelf vnicType: description: |- vnicType specifies the type of vNIC which this port should be @@ -384,6 +477,14 @@ spec: set to Disabled rule: 'has(self.portSecurity) && self.portSecurity == ''Disabled'' ? !has(self.allowedAddressPairs) : true' + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -481,6 +582,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -553,6 +663,10 @@ spec: maxItems: 128 type: array x-kubernetes-list-type: atomic + hostID: + description: hostID is the ID of host where the port resides. + maxLength: 128 + type: string macAddress: description: macAddress is the MAC address of the port. maxLength: 1024 @@ -604,6 +718,12 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: atomic + trustedVIF: + description: |- + trustedVIF indicates whether the VF for the port will become + trusted by physical function to perform some privileged + operations. + type: boolean updatedAt: description: updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 @@ -616,6 +736,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_projects.yaml b/config/crd/bases/openstack.k-orc.cloud_projects.yaml index ab550af2b..f2ac9df09 100644 --- a/config/crd/bases/openstack.k-orc.cloud_projects.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_projects.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: projects.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -91,6 +91,12 @@ spec: error state and will not continue to retry. minProperties: 1 properties: + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string name: description: name of the existing resource maxLength: 64 @@ -148,6 +154,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -194,6 +201,15 @@ spec: maxLength: 65535 minLength: 1 type: string + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: domainRef is immutable + rule: self == oldSelf enabled: description: enabled defines whether a project is enabled or not. Default is true. @@ -217,6 +233,14 @@ spec: type: array x-kubernetes-list-type: set type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -314,6 +338,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -324,6 +357,11 @@ spec: resource. maxLength: 65535 type: string + domainID: + description: domainID is the ID of the Domain to which the resource + is associated. + maxLength: 1024 + type: string enabled: description: enabled represents whether a project is enabled or not. @@ -343,6 +381,8 @@ spec: x-kubernetes-list-type: atomic type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_roleassignments.yaml b/config/crd/bases/openstack.k-orc.cloud_roleassignments.yaml new file mode 100644 index 000000000..7902807d1 --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_roleassignments.yaml @@ -0,0 +1,347 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: roleassignments.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: RoleAssignment + listKind: RoleAssignmentList + plural: roleassignments + singular: roleassignment + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: RoleAssignment is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + domainRef: + description: domainRef filters by the referenced Domain scope. + maxLength: 253 + minLength: 1 + type: string + groupRef: + description: groupRef filters by the referenced Group. + maxLength: 253 + minLength: 1 + type: string + projectRef: + description: projectRef filters by the referenced Project + scope. + maxLength: 253 + minLength: 1 + type: string + roleRef: + description: roleRef filters by the referenced Role. + maxLength: 253 + minLength: 1 + type: string + userRef: + description: userRef filters by the referenced User. + maxLength: 253 + minLength: 1 + type: string + type: object + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + domainRef: + description: |- + domainRef references the Domain scope for the assignment. + Exactly one of projectRef or domainRef must be specified. + maxLength: 253 + minLength: 1 + type: string + groupRef: + description: |- + groupRef references the Group receiving the role assignment. + Exactly one of userRef or groupRef must be specified. + maxLength: 253 + minLength: 1 + type: string + projectRef: + description: |- + projectRef references the Project scope for the assignment. + Exactly one of projectRef or domainRef must be specified. + maxLength: 253 + minLength: 1 + type: string + roleRef: + description: roleRef references the Role being assigned. + maxLength: 253 + minLength: 1 + type: string + userRef: + description: |- + userRef references the User receiving the role assignment. + Exactly one of userRef or groupRef must be specified. + maxLength: 253 + minLength: 1 + type: string + required: + - roleRef + type: object + x-kubernetes-validations: + - message: exactly one of userRef or groupRef is required + rule: (has(self.userRef) && !has(self.groupRef)) || (!has(self.userRef) + && has(self.groupRef)) + - message: exactly one of projectRef or domainRef is required + rule: (has(self.projectRef) && !has(self.domainRef)) || (!has(self.projectRef) + && has(self.domainRef)) + - message: RoleAssignmentResourceSpec is immutable + rule: self == oldSelf + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + domainID: + description: domainID is the OpenStack ID of the domain scope + (if scopeType is Domain). + maxLength: 1024 + type: string + groupID: + description: groupID is the OpenStack ID of the group (if actorType + is Group). + maxLength: 1024 + type: string + projectID: + description: projectID is the OpenStack ID of the project scope + (if scopeType is Project). + maxLength: 1024 + type: string + roleID: + description: roleID is the OpenStack ID of the assigned role. + maxLength: 1024 + type: string + userID: + description: userID is the OpenStack ID of the user (if actorType + is User). + maxLength: 1024 + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/openstack.k-orc.cloud_roles.yaml b/config/crd/bases/openstack.k-orc.cloud_roles.yaml index 98cb4993d..12fbcd4dc 100644 --- a/config/crd/bases/openstack.k-orc.cloud_roles.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_roles.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: roles.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -109,6 +109,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -172,6 +173,14 @@ spec: minLength: 1 type: string type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -269,6 +278,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -291,6 +309,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_routerinterfaces.yaml b/config/crd/bases/openstack.k-orc.cloud_routerinterfaces.yaml index 83075e0c7..3fde7b424 100644 --- a/config/crd/bases/openstack.k-orc.cloud_routerinterfaces.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_routerinterfaces.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: routerinterfaces.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -50,6 +50,14 @@ spec: spec: description: spec specifies the desired state of the resource. properties: + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string routerRef: description: routerRef references the router to which this interface belongs. @@ -77,8 +85,13 @@ spec: - message: subnetRef is required when type is 'Subnet' and not permitted otherwise rule: 'self.type == ''Subnet'' ? has(self.subnetRef) : !has(self.subnetRef)' - - message: RouterInterfaceResourceSpec is immutable - rule: self == oldSelf + - message: type is immutable + rule: self.type == oldSelf.type + - message: routerRef is immutable + rule: self.routerRef == oldSelf.routerRef + - message: subnetRef is immutable + rule: has(self.subnetRef) == has(oldSelf.subnetRef) && (!has(self.subnetRef) + || self.subnetRef == oldSelf.subnetRef) status: description: status defines the observed state of the resource. properties: @@ -161,7 +174,15 @@ spec: router interface maxLength: 1024 type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + of the resource. + format: date-time + type: string type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_routers.yaml b/config/crd/bases/openstack.k-orc.cloud_routers.yaml index 870aee9db..520d0b258 100644 --- a/config/crd/bases/openstack.k-orc.cloud_routers.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_routers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: routers.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -173,6 +173,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -299,6 +300,14 @@ spec: type: array x-kubernetes-list-type: set type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -396,6 +405,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -458,6 +476,8 @@ spec: x-kubernetes-list-type: atomic type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_securitygroups.yaml b/config/crd/bases/openstack.k-orc.cloud_securitygroups.yaml index 13cef5e35..31ecafd59 100644 --- a/config/crd/bases/openstack.k-orc.cloud_securitygroups.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_securitygroups.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: securitygroups.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -173,6 +173,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -374,6 +375,14 @@ spec: type: array x-kubernetes-list-type: set type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -471,6 +480,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -588,6 +606,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_servergroups.yaml b/config/crd/bases/openstack.k-orc.cloud_servergroups.yaml index ad2eafd83..1bd83c87a 100644 --- a/config/crd/bases/openstack.k-orc.cloud_servergroups.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_servergroups.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: servergroups.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -104,6 +104,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -180,6 +181,14 @@ spec: policy rule: 'has(self.rules) && self.rules.maxServerPerHost > 0 ? self.policy == ''anti-affinity'' : true' + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -277,6 +286,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -311,6 +329,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_servers.yaml b/config/crd/bases/openstack.k-orc.cloud_servers.yaml index c9feaab67..19563cd1c 100644 --- a/config/crd/bases/openstack.k-orc.cloud_servers.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_servers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: servers.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -154,6 +154,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -202,6 +203,38 @@ spec: x-kubernetes-validations: - message: availabilityZone is immutable rule: self == oldSelf + bootVolume: + description: |- + bootVolume specifies a volume to boot from instead of an image. + When specified, imageRef must be omitted. The volume must be + bootable (created from an image using imageRef in the Volume spec). + properties: + tag: + description: tag is the device tag applied to the volume. + maxLength: 255 + type: string + volumeRef: + description: |- + volumeRef is a reference to a Volume object. The volume must be + bootable (created from an image) and available before server creation. + maxLength: 253 + minLength: 1 + type: string + required: + - volumeRef + type: object + x-kubernetes-validations: + - message: bootVolume is immutable + rule: self == oldSelf + configDrive: + description: |- + configDrive specifies whether to attach a config drive to the server. + When true, configuration data will be available via a special drive + instead of the metadata service. + type: boolean + x-kubernetes-validations: + - message: configDrive is immutable + rule: self == oldSelf flavorRef: description: flavorRef references the flavor to use for the server instance. @@ -214,7 +247,7 @@ spec: imageRef: description: |- imageRef references the image to use for the server instance. - NOTE: This is not required in case of boot from volume. + This field is required unless bootVolume is specified for boot-from-volume. maxLength: 253 minLength: 1 type: string @@ -231,6 +264,30 @@ spec: x-kubernetes-validations: - message: keypairRef is immutable rule: self == oldSelf + metadata: + description: metadata is a list of metadata key-value pairs which + will be set on the server. + items: + description: ServerMetadata represents a key-value pair for + server metadata. + properties: + key: + description: key is the metadata key. + maxLength: 255 + minLength: 1 + type: string + value: + description: value is the metadata value. + maxLength: 255 + minLength: 1 + type: string + required: + - key + - value + type: object + maxItems: 128 + type: array + x-kubernetes-list-type: atomic name: description: |- name will be the name of the created resource. If not specified, the @@ -257,15 +314,78 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: atomic - serverGroupRef: - description: |- - serverGroupRef is a reference to a ServerGroup object. The server - will be created in the server group. - maxLength: 253 - minLength: 1 - type: string + schedulerHints: + description: schedulerHints provides hints to the Nova scheduler + for server placement. + properties: + additionalProperties: + additionalProperties: + type: string + description: |- + additionalProperties is a map of arbitrary key/value pairs that are + not validated by Nova. + type: object + buildNearHostIP: + description: |- + buildNearHostIP specifies a subnet of compute nodes to host the server. + The host IP should be provided in an CIDR format like 10.10.10.10/24. + format: cidr + maxLength: 49 + minLength: 1 + type: string + differentCell: + description: |- + differentCell is a list of cell names where the server should not + be placed. + items: + maxLength: 1024 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + differentHostServerRefs: + description: |- + differentHostServerRefs is a list of references to Server objects. + The server will be scheduled on a different host than all specified servers. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + query: + description: |- + query is a conditional statement that results in compute nodes + able to host the server. + maxLength: 1024 + type: string + sameHostServerRefs: + description: |- + sameHostServerRefs is a list of references to Server objects. + The server will be scheduled on the same host as all specified servers. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + serverGroupRef: + description: |- + serverGroupRef is a reference to a ServerGroup object. The server will be + scheduled on a host in the specified server group. + maxLength: 253 + minLength: 1 + type: string + targetCell: + description: targetCell is a cell name where the server will + be placed. + maxLength: 255 + type: string + type: object x-kubernetes-validations: - - message: serverGroupRef is immutable + - message: schedulerHints is immutable rule: self == oldSelf tags: description: tags is a list of tags which will be applied to the @@ -321,9 +441,21 @@ spec: x-kubernetes-list-type: atomic required: - flavorRef - - imageRef - ports type: object + x-kubernetes-validations: + - message: either imageRef or bootVolume must be specified + rule: has(self.imageRef) || has(self.bootVolume) + - message: imageRef and bootVolume are mutually exclusive + rule: '!(has(self.imageRef) && has(self.bootVolume))' + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -421,6 +553,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -431,6 +572,10 @@ spec: server is located. maxLength: 1024 type: string + configDrive: + description: configDrive indicates whether the server was booted + with a config drive. + type: boolean hostID: description: hostID is the host where the server is located in the cloud. @@ -488,6 +633,25 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: atomic + metadata: + description: metadata is the list of metadata key-value pairs + on the resource. + items: + description: ServerMetadataStatus represents a key-value pair + for server metadata in status. + properties: + key: + description: key is the metadata key. + maxLength: 255 + type: string + value: + description: value is the metadata value. + maxLength: 255 + type: string + type: object + maxItems: 128 + type: array + x-kubernetes-list-type: atomic name: description: name is the human-readable name of the resource. Might not be unique. @@ -532,6 +696,8 @@ spec: x-kubernetes-list-type: atomic type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_services.yaml b/config/crd/bases/openstack.k-orc.cloud_services.yaml index 9e6a16416..3b6b4ac25 100644 --- a/config/crd/bases/openstack.k-orc.cloud_services.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_services.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: services.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -109,6 +109,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -176,6 +177,14 @@ spec: required: - type type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -273,6 +282,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -297,6 +315,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_sharenetworks.yaml b/config/crd/bases/openstack.k-orc.cloud_sharenetworks.yaml new file mode 100644 index 000000000..907ab70f9 --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_sharenetworks.yaml @@ -0,0 +1,365 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: sharenetworks.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: ShareNetwork + listKind: ShareNetworkList + plural: sharenetworks + singular: sharenetwork + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ShareNetwork is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + description: + description: description of the existing resource + maxLength: 255 + minLength: 1 + type: string + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + networkRef: + description: networkRef is a reference to the ORC Network which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: networkRef is immutable + rule: self == oldSelf + subnetRef: + description: subnetRef is a reference to the ORC Subnet which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: subnetRef is immutable + rule: self == oldSelf + type: object + x-kubernetes-validations: + - message: networkRef and subnetRef must be specified together + rule: has(self.networkRef) == has(self.subnetRef) + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + cidr: + description: cidr is the CIDR of the subnet. + maxLength: 1024 + type: string + createdAt: + description: createdAt shows the date and time when the resource + was created. + format: date-time + type: string + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + ipVersion: + description: ipVersion is the IP version (4 or 6). + format: int32 + type: integer + name: + description: name is a Human-readable name for the resource. + maxLength: 1024 + type: string + networkType: + description: networkType is the network type (e.g., vlan, vxlan, + flat). + maxLength: 1024 + type: string + neutronNetID: + description: neutronNetID is the Neutron network ID. + maxLength: 1024 + type: string + neutronSubnetID: + description: neutronSubnetID is the Neutron subnet ID. + maxLength: 1024 + type: string + projectID: + description: projectID is the ID of the project that owns the + share network. + maxLength: 1024 + type: string + segmentationID: + description: segmentationID is the segmentation ID of the network. + format: int32 + type: integer + updatedAt: + description: updatedAt shows the date and time when the resource + was updated. + format: date-time + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/openstack.k-orc.cloud_subnets.yaml b/config/crd/bases/openstack.k-orc.cloud_subnets.yaml index e0445ee80..0a6e97abc 100644 --- a/config/crd/bases/openstack.k-orc.cloud_subnets.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_subnets.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: subnets.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -220,6 +220,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -465,6 +466,14 @@ spec: - ipVersion - networkRef type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -562,6 +571,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -695,6 +713,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_trunks.yaml b/config/crd/bases/openstack.k-orc.cloud_trunks.yaml new file mode 100644 index 000000000..da9407964 --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_trunks.yaml @@ -0,0 +1,522 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: trunks.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: Trunk + listKind: TrunkList + plural: trunks + singular: trunk + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Trunk is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + adminStateUp: + description: adminStateUp is the administrative state of the + trunk. + type: boolean + description: + description: description of the existing resource + maxLength: 255 + minLength: 1 + type: string + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + notTags: + description: |- + notTags is a list of tags to filter by. If specified, resources which + contain all of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + notTagsAny: + description: |- + notTagsAny is a list of tags to filter by. If specified, resources + which contain any of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + portRef: + description: portRef is a reference to the ORC Port which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + projectRef: + description: projectRef is a reference to the ORC Project + which this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + tags: + description: |- + tags is a list of tags to filter by. If specified, the resource must + have all of the tags specified to be included in the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + tagsAny: + description: |- + tagsAny is a list of tags to filter by. If specified, the resource + must have at least one of the tags specified to be included in the + result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + adminStateUp: + description: |- + adminStateUp is the administrative state of the trunk. If false (down), + the trunk does not forward packets. + type: boolean + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + portRef: + description: portRef is a reference to the ORC Port which this + resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: portRef is immutable + rule: self == oldSelf + projectRef: + description: projectRef is a reference to the ORC Project which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: projectRef is immutable + rule: self == oldSelf + subports: + description: subports is the list of ports to attach to the trunk. + items: + description: |- + TrunkSubportSpec represents a subport to attach to a trunk. + It maps to gophercloud's trunks.Subport. + properties: + portRef: + description: portRef is a reference to the ORC Port that + will be attached as a subport. + maxLength: 253 + minLength: 1 + type: string + segmentationID: + description: segmentationID is the segmentation ID for the + subport (e.g. VLAN ID). + format: int32 + maximum: 4094 + minimum: 1 + type: integer + segmentationType: + description: segmentationType is the segmentation type for + the subport (e.g. vlan). + enum: + - inherit + - vlan + maxLength: 32 + minLength: 1 + type: string + required: + - portRef + - segmentationID + - segmentationType + type: object + maxItems: 1024 + type: array + x-kubernetes-list-type: atomic + tags: + description: tags is a list of Neutron tags to apply to the trunk. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + required: + - portRef + type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + adminStateUp: + description: adminStateUp is the administrative state of the trunk. + type: boolean + createdAt: + description: createdAt shows the date and time when the resource + was created. The date and time stamp format is ISO 8601 + format: date-time + type: string + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + name: + description: name is a Human-readable name for the resource. Might + not be unique. + maxLength: 1024 + type: string + portID: + description: portID is the ID of the Port to which the resource + is associated. + maxLength: 1024 + type: string + projectID: + description: projectID is the ID of the Project to which the resource + is associated. + maxLength: 1024 + type: string + revisionNumber: + description: revisionNumber optionally set via extensions/standard-attr-revisions + format: int64 + type: integer + status: + description: status indicates whether the trunk is currently operational. + maxLength: 1024 + type: string + subports: + description: subports is a list of ports associated with the trunk. + items: + description: |- + TrunkSubportStatus represents an attached subport on a trunk. + It maps to gophercloud's trunks.Subport. + properties: + portID: + description: portID is the OpenStack ID of the Port attached + as a subport. + maxLength: 1024 + type: string + segmentationID: + description: segmentationID is the segmentation ID for the + subport (e.g. VLAN ID). + format: int32 + type: integer + segmentationType: + description: segmentationType is the segmentation type for + the subport (e.g. vlan). + maxLength: 1024 + type: string + type: object + maxItems: 1024 + type: array + x-kubernetes-list-type: atomic + tags: + description: tags is the list of tags on the resource. + items: + maxLength: 1024 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + tenantID: + description: tenantID is the project owner of the trunk (alias + of projectID in some deployments). + maxLength: 1024 + type: string + updatedAt: + description: updatedAt shows the date and time when the resource + was updated. The date and time stamp format is ISO 8601 + format: date-time + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/openstack.k-orc.cloud_users.yaml b/config/crd/bases/openstack.k-orc.cloud_users.yaml new file mode 100644 index 000000000..7f872c6d2 --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_users.yaml @@ -0,0 +1,362 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: users.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: User + listKind: UserList + plural: users + singular: user + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: User is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + defaultProjectRef: + description: defaultProjectRef is a reference to the Default Project + which this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: defaultProjectRef is immutable + rule: self == oldSelf + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: domainRef is immutable + rule: self == oldSelf + enabled: + description: enabled defines whether a user is enabled or disabled + type: boolean + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + passwordRef: + description: |- + passwordRef is a reference to a Secret containing the password + for this user. The Secret must contain a key named "password". + If not specified, the user is created without a password. + maxLength: 253 + minLength: 1 + type: string + type: object + x-kubernetes-validations: + - message: passwordRef may not be removed once set + rule: '!has(oldSelf.passwordRef) || has(self.passwordRef)' + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + appliedPasswordRef: + description: |- + appliedPasswordRef is the name of the Secret containing the + password that was last applied to the OpenStack resource. + maxLength: 1024 + type: string + defaultProjectID: + description: defaultProjectID is the ID of the Default Project + to which the user is associated with. + maxLength: 1024 + type: string + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + domainID: + description: domainID is the ID of the Domain to which the resource + is associated. + maxLength: 1024 + type: string + enabled: + description: enabled defines whether a user is enabled or disabled + type: boolean + name: + description: name is a Human-readable name for the resource. Might + not be unique. + maxLength: 1024 + type: string + passwordExpiresAt: + description: passwordExpiresAt is the timestamp at which the user's + password expires. + maxLength: 1024 + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/openstack.k-orc.cloud_volumes.yaml b/config/crd/bases/openstack.k-orc.cloud_volumes.yaml index aca503047..a740ea21e 100644 --- a/config/crd/bases/openstack.k-orc.cloud_volumes.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_volumes.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: volumes.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -119,6 +119,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -173,6 +174,17 @@ spec: maxLength: 255 minLength: 1 type: string + imageRef: + description: |- + imageRef is a reference to an ORC Image. If specified, creates a + bootable volume from this image. The volume size must be >= the + image's min_disk requirement. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: imageRef is immutable + rule: self == oldSelf metadata: description: |- metadata key and value pairs to be associated with the volume. @@ -226,6 +238,14 @@ spec: required: - size type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -323,6 +343,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -389,6 +418,11 @@ spec: description: host is the identifier of the host holding the volume. maxLength: 1024 type: string + imageID: + description: imageID is the ID of the image this volume was created + from, if any. + maxLength: 1024 + type: string metadata: description: metadata key and value pairs to be associated with the volume. @@ -456,6 +490,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/bases/openstack.k-orc.cloud_volumetypes.yaml b/config/crd/bases/openstack.k-orc.cloud_volumetypes.yaml index c92df01fc..1ba9b060f 100644 --- a/config/crd/bases/openstack.k-orc.cloud_volumetypes.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_volumetypes.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: volumetypes.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -113,6 +113,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -191,6 +192,14 @@ spec: pattern: ^[^,]+$ type: string type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string required: - cloudCredentialsRef type: object @@ -288,6 +297,15 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time type: string resource: description: resource contains the observed state of the OpenStack @@ -325,6 +343,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 33b8c85e2..9c133d11c 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,7 +3,10 @@ # since it depends on service name and namespace that are out of this kustomize package. # It should be run by config/default resources: +- bases/openstack.k-orc.cloud_addressscopes.yaml +- bases/openstack.k-orc.cloud_applicationcredentials.yaml - bases/openstack.k-orc.cloud_domains.yaml +- bases/openstack.k-orc.cloud_endpoints.yaml - bases/openstack.k-orc.cloud_flavors.yaml - bases/openstack.k-orc.cloud_floatingips.yaml - bases/openstack.k-orc.cloud_groups.yaml @@ -13,13 +16,17 @@ resources: - bases/openstack.k-orc.cloud_ports.yaml - bases/openstack.k-orc.cloud_projects.yaml - bases/openstack.k-orc.cloud_roles.yaml +- bases/openstack.k-orc.cloud_roleassignments.yaml - bases/openstack.k-orc.cloud_routers.yaml - bases/openstack.k-orc.cloud_routerinterfaces.yaml - bases/openstack.k-orc.cloud_securitygroups.yaml - bases/openstack.k-orc.cloud_servers.yaml - bases/openstack.k-orc.cloud_servergroups.yaml - bases/openstack.k-orc.cloud_services.yaml +- bases/openstack.k-orc.cloud_sharenetworks.yaml - bases/openstack.k-orc.cloud_subnets.yaml +- bases/openstack.k-orc.cloud_trunks.yaml +- bases/openstack.k-orc.cloud_users.yaml - bases/openstack.k-orc.cloud_volumes.yaml - bases/openstack.k-orc.cloud_volumetypes.yaml # +kubebuilder:scaffold:crdkustomizeresource diff --git a/config/manifests/bases/orc.clusterserviceversion.yaml b/config/manifests/bases/orc.clusterserviceversion.yaml index 0c5f1c0ea..410c09b66 100644 --- a/config/manifests/bases/orc.clusterserviceversion.yaml +++ b/config/manifests/bases/orc.clusterserviceversion.yaml @@ -19,11 +19,26 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: AddressScope is the Schema for an ORC resource. + displayName: Address Scope + kind: AddressScope + name: addressscopes.openstack.k-orc.cloud + version: v1alpha1 + - description: ApplicationCredential is the Schema for an ORC resource. + displayName: Application Credential + kind: ApplicationCredential + name: applicationcredentials.openstack.k-orc.cloud + version: v1alpha1 - description: Domain is the Schema for an ORC resource. displayName: Domain kind: Domain name: domains.openstack.k-orc.cloud version: v1alpha1 + - description: Endpoint is the Schema for an ORC resource. + displayName: Endpoint + kind: Endpoint + name: endpoints.openstack.k-orc.cloud + version: v1alpha1 - description: Flavor is the Schema for an ORC resource. displayName: Flavor kind: Flavor @@ -64,6 +79,11 @@ spec: kind: Project name: projects.openstack.k-orc.cloud version: v1alpha1 + - description: RoleAssignment is the Schema for an ORC resource. + displayName: Role Assignment + kind: RoleAssignment + name: roleassignments.openstack.k-orc.cloud + version: v1alpha1 - description: Role is the Schema for an ORC resource. displayName: Role kind: Role @@ -99,11 +119,26 @@ spec: kind: Service name: services.openstack.k-orc.cloud version: v1alpha1 + - description: ShareNetwork is the Schema for an ORC resource. + displayName: Share Network + kind: ShareNetwork + name: sharenetworks.openstack.k-orc.cloud + version: v1alpha1 - description: Subnet is the Schema for an ORC resource. displayName: Subnet kind: Subnet name: subnets.openstack.k-orc.cloud version: v1alpha1 + - description: Trunk is the Schema for an ORC resource. + displayName: Trunk + kind: Trunk + name: trunks.openstack.k-orc.cloud + version: v1alpha1 + - description: User is the Schema for an ORC resource. + displayName: User + kind: User + name: users.openstack.k-orc.cloud + version: v1alpha1 - description: Volume is the Schema for an ORC resource. displayName: Volume kind: Volume diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 5a0a7443b..a04a488e2 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -17,7 +17,10 @@ rules: - apiGroups: - openstack.k-orc.cloud resources: + - addressscopes + - applicationcredentials - domains + - endpoints - flavors - floatingips - groups @@ -26,6 +29,7 @@ rules: - networks - ports - projects + - roleassignments - roles - routerinterfaces - routers @@ -33,7 +37,10 @@ rules: - servergroups - servers - services + - sharenetworks - subnets + - trunks + - users - volumes - volumetypes verbs: @@ -47,7 +54,10 @@ rules: - apiGroups: - openstack.k-orc.cloud resources: + - addressscopes/status + - applicationcredentials/status - domains/status + - endpoints/status - flavors/status - floatingips/status - groups/status @@ -56,6 +66,7 @@ rules: - networks/status - ports/status - projects/status + - roleassignments/status - roles/status - routerinterfaces/status - routers/status @@ -63,7 +74,10 @@ rules: - servergroups/status - servers/status - services/status + - sharenetworks/status - subnets/status + - trunks/status + - users/status - volumes/status - volumetypes/status verbs: diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index dac467c69..ceb05e15e 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,7 +1,10 @@ # Code generated by resource-generator. DO NOT EDIT. ## Append samples of your project ## resources: +- openstack_v1alpha1_addressscope.yaml +- openstack_v1alpha1_applicationcredential.yaml - openstack_v1alpha1_domain.yaml +- openstack_v1alpha1_endpoint.yaml - openstack_v1alpha1_flavor.yaml - openstack_v1alpha1_floatingip.yaml - openstack_v1alpha1_group.yaml @@ -11,13 +14,17 @@ resources: - openstack_v1alpha1_port.yaml - openstack_v1alpha1_project.yaml - openstack_v1alpha1_role.yaml +- openstack_v1alpha1_roleassignment.yaml - openstack_v1alpha1_router.yaml - openstack_v1alpha1_routerinterface.yaml - openstack_v1alpha1_securitygroup.yaml - openstack_v1alpha1_server.yaml - openstack_v1alpha1_servergroup.yaml - openstack_v1alpha1_service.yaml +- openstack_v1alpha1_sharenetwork.yaml - openstack_v1alpha1_subnet.yaml +- openstack_v1alpha1_trunk.yaml +- openstack_v1alpha1_user.yaml - openstack_v1alpha1_volume.yaml - openstack_v1alpha1_volumetype.yaml # +kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/openstack_v1alpha1_addressscope.yaml b/config/samples/openstack_v1alpha1_addressscope.yaml new file mode 100644 index 000000000..16435fac3 --- /dev/null +++ b/config/samples/openstack_v1alpha1_addressscope.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-sample +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 diff --git a/config/samples/openstack_v1alpha1_applicationcredential.yaml b/config/samples/openstack_v1alpha1_applicationcredential.yaml new file mode 100644 index 000000000..d2fca282b --- /dev/null +++ b/config/samples/openstack_v1alpha1_applicationcredential.yaml @@ -0,0 +1,59 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: appcred-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: appcred-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: appcred-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + type: "compute" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: appcred-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Sample Application Credential + userRef: appcred-sample + unrestricted: true + secretRef: kubernetes-secret + roleRefs: + - appcred-sample + accessRules: + - method: "GET" + serviceRef: appcred-sample + path: "/v2.1/servers" + expiresAt: "2033-03-03T22:22:22Z" diff --git a/config/samples/openstack_v1alpha1_domain.yaml b/config/samples/openstack_v1alpha1_domain.yaml index 7903d0fb8..0ea0bdbc3 100644 --- a/config/samples/openstack_v1alpha1_domain.yaml +++ b/config/samples/openstack_v1alpha1_domain.yaml @@ -5,10 +5,9 @@ metadata: name: domain-sample spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: description: Sample Domain - # TODO(scaffolding): Add all fields the resource supports + enabled: true diff --git a/config/samples/openstack_v1alpha1_endpoint.yaml b/config/samples/openstack_v1alpha1_endpoint.yaml new file mode 100644 index 000000000..9fc4edd13 --- /dev/null +++ b/config/samples/openstack_v1alpha1_endpoint.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + interface: internal + url: "https://example.com" + serviceRef: service-sample diff --git a/config/samples/openstack_v1alpha1_flavor.yaml b/config/samples/openstack_v1alpha1_flavor.yaml index 87990fb6c..c46f5bc5e 100644 --- a/config/samples/openstack_v1alpha1_flavor.yaml +++ b/config/samples/openstack_v1alpha1_flavor.yaml @@ -15,3 +15,8 @@ spec: swap: 2 isPublic: false ephemeral: 1 + extraSpecs: + - name: spec1 + value: foo + - name: spec2 + value: bar diff --git a/config/samples/openstack_v1alpha1_roleassignment.yaml b/config/samples/openstack_v1alpha1_roleassignment.yaml new file mode 100644 index 000000000..876c748b9 --- /dev/null +++ b/config/samples/openstack_v1alpha1_roleassignment.yaml @@ -0,0 +1,49 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-sample-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-sample-role +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Group +metadata: + name: roleassignment-sample-group +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-sample-group +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-sample-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-sample-project +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-sample-role + groupRef: roleassignment-sample-group + projectRef: roleassignment-sample-project diff --git a/config/samples/openstack_v1alpha1_server.yaml b/config/samples/openstack_v1alpha1_server.yaml index 29691f536..0ee8c24ff 100644 --- a/config/samples/openstack_v1alpha1_server.yaml +++ b/config/samples/openstack_v1alpha1_server.yaml @@ -14,9 +14,16 @@ spec: - portRef: server-sample volumes: - volumeRef: server-sample - serverGroupRef: server-sample keypairRef: server-sample + schedulerHints: + serverGroupRef: server-sample availabilityZone: nova tags: - tag1 - tag2 + metadata: + - key: environment + value: development + - key: owner + value: sample + configDrive: true diff --git a/config/samples/openstack_v1alpha1_server_boot_from_volume.yaml b/config/samples/openstack_v1alpha1_server_boot_from_volume.yaml new file mode 100644 index 000000000..a63d01abc --- /dev/null +++ b/config/samples/openstack_v1alpha1_server_boot_from_volume.yaml @@ -0,0 +1,25 @@ +# Example of creating a server that boots from a Cinder volume instead of an image. +# This is the boot-from-volume (BFV) pattern. +# +# Prerequisites: +# - A bootable volume created from an image (see openstack_v1alpha1_volume_bootable.yaml) +# - Network, subnet, and port resources +# - A flavor +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Server +metadata: + name: server-boot-from-volume-sample +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + # Note: No imageRef - booting from volume instead + bootVolume: + volumeRef: bootable-volume-sample + flavorRef: server-sample + ports: + - portRef: server-sample + availabilityZone: nova diff --git a/config/samples/openstack_v1alpha1_sharenetwork.yaml b/config/samples/openstack_v1alpha1_sharenetwork.yaml new file mode 100644 index 000000000..cd045a6a2 --- /dev/null +++ b/config/samples/openstack_v1alpha1_sharenetwork.yaml @@ -0,0 +1,45 @@ +--- +# Create a Network for the ShareNetwork +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-sample +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Network for ShareNetwork sample +--- +# Create a Subnet for the ShareNetwork +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-sample +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-sample + ipVersion: 4 + cidr: 192.168.100.0/24 + description: Subnet for ShareNetwork sample +--- +# Create a ShareNetwork for Manila shares +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-sample +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: my-share-network + description: Sample ShareNetwork for Manila shared filesystems + networkRef: sharenetwork-sample + subnetRef: sharenetwork-sample diff --git a/config/samples/openstack_v1alpha1_trunk.yaml b/config/samples/openstack_v1alpha1_trunk.yaml new file mode 100644 index 000000000..7019315f1 --- /dev/null +++ b/config/samples/openstack_v1alpha1_trunk.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-sample +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Sample Trunk + name: trunk-sample-name + portRef: my-port + subPorts: + - portRef: sub-port-1 + segmentationID: 101 + segmentationType: vlan + - portRef: sub-port-2 + segmentationID: 102 + segmentationType: vlan + tags: + - tag1 + - tag2 diff --git a/config/samples/openstack_v1alpha1_user.yaml b/config/samples/openstack_v1alpha1_user.yaml new file mode 100644 index 000000000..2e6371f2f --- /dev/null +++ b/config/samples/openstack_v1alpha1_user.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: user-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: v1 +kind: Secret +metadata: + name: user-sample +type: Opaque +stringData: + password: "TestPassword" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: user-sample + description: User sample + domainRef: user-sample + defaultProjectRef: user-sample + enabled: true + passwordRef: user-sample diff --git a/config/samples/openstack_v1alpha1_volume.yaml b/config/samples/openstack_v1alpha1_volume.yaml index 08f5d608b..98cebd526 100644 --- a/config/samples/openstack_v1alpha1_volume.yaml +++ b/config/samples/openstack_v1alpha1_volume.yaml @@ -12,6 +12,7 @@ spec: description: Sample Volume size: 100 volumeTypeRef: my-volume-type + imageRef: ubuntu-2404 metadata: key1: value1 key2: value2 diff --git a/config/samples/openstack_v1alpha1_volumetype.yaml b/config/samples/openstack_v1alpha1_volumetype.yaml index 1e8ee928e..77c8d458d 100644 --- a/config/samples/openstack_v1alpha1_volumetype.yaml +++ b/config/samples/openstack_v1alpha1_volumetype.yaml @@ -12,5 +12,7 @@ spec: description: Sample VolumeType isPublic: false extraSpecs: - spec1: "foo" - spec2: "bar" + - name: spec1 + value: foo + - name: spec2 + value: bar diff --git a/dist/install.yaml b/dist/install.yaml index b2eefc2f4..5c3d896fa 100644 --- a/dist/install.yaml +++ b/dist/install.yaml @@ -11,17 +11,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: domains.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: addressscopes.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: Domain - listKind: DomainList - plural: domains - singular: domain + kind: AddressScope + listKind: AddressScopeList + plural: addressscopes + singular: addressscope scope: Namespaced versions: - additionalPrinterColumns: @@ -40,7 +40,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Domain is the Schema for an ORC resource. + description: AddressScope is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -99,16 +99,31 @@ spec: error state and will not continue to retry. minProperties: 1 properties: - enabled: - description: |- - enabled defines whether a domain is enabled or not. Default is true. - Note: Users can only authorize against an enabled domain (and any of its projects). - type: boolean + ipVersion: + description: ipVersion is the IP protocol version. + enum: + - 4 + - 6 + format: int32 + type: integer name: description: name of the existing resource - maxLength: 64 + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + projectRef: + description: projectRef is a reference to the ORC Project + which this resource is associated with. + maxLength: 253 minLength: 1 type: string + shared: + description: |- + shared indicates whether this resource is shared across all + projects or not. By default, only admin users can change set + this value. + type: boolean type: object id: description: |- @@ -116,6 +131,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -156,24 +172,45 @@ spec: resource must be specified if the management policy is `managed`. properties: - description: - description: description is a human-readable description for the - resource. - maxLength: 255 - minLength: 1 - type: string - enabled: - description: |- - enabled defines whether a domain is enabled or not. Default is true. - Note: Users can only authorize against an enabled domain (and any of its projects). - type: boolean + ipVersion: + description: ipVersion is the IP protocol version. + enum: + - 4 + - 6 + format: int32 + type: integer + x-kubernetes-validations: + - message: ipVersion is immutable + rule: self == oldSelf name: description: |- name will be the name of the created resource. If not specified, the name of the ORC object will be used. - maxLength: 64 + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + projectRef: + description: projectRef is a reference to the ORC Project which + this resource is associated with. + maxLength: 253 minLength: 1 type: string + x-kubernetes-validations: + - message: projectRef is immutable + rule: self == oldSelf + shared: + description: |- + shared indicates whether this resource is shared across all + projects or not. By default, only admin users can change set + this value. We can't unshared a shared address scope; Neutron + enforces this. + type: boolean + x-kubernetes-validations: + - message: shared address scope can't be unshared + rule: '!(oldSelf && !self)' + required: + - ipVersion type: object required: - cloudCredentialsRef @@ -272,28 +309,36 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack resource. properties: - description: - description: description is a human-readable description for the - resource. - maxLength: 1024 - type: string - enabled: - description: |- - enabled defines whether a domain is enabled or not. Default is true. - Note: Users can only authorize against an enabled domain (and any of its projects). - type: boolean + ipVersion: + description: ipVersion is the IP protocol version. + format: int32 + type: integer name: description: name is a Human-readable name for the resource. Might not be unique. maxLength: 1024 type: string + projectID: + description: projectID is the ID of the Project to which the resource + is associated. + maxLength: 1024 + type: string + shared: + description: |- + shared indicates whether this resource is shared across all + projects or not. By default, only admin users can change set + this value. + type: boolean type: object type: object + required: + - spec type: object served: true storage: true @@ -304,17 +349,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: flavors.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: applicationcredentials.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: Flavor - listKind: FlavorList - plural: flavors - singular: flavor + kind: ApplicationCredential + listKind: ApplicationCredentialList + plural: applicationcredentials + singular: applicationcredential scope: Namespaced versions: - additionalPrinterColumns: @@ -333,7 +378,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Flavor is the Schema for an ORC resource. + description: ApplicationCredential is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -390,30 +435,27 @@ spec: result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry. - minProperties: 1 + minProperties: 2 properties: - disk: - description: disk is the size of the root disk in GiB. - format: int32 - minimum: 0 - type: integer + description: + description: description of the existing resource + maxLength: 1024 + type: string name: description: name of the existing resource maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - ram: - description: ram is the memory of the flavor, measured in - MB. - format: int32 - minimum: 1 - type: integer - vcpus: - description: vcpus is the number of vcpus for the flavor. - format: int32 - minimum: 1 - type: integer + userRef: + description: |- + userRef is a reference to the ORC User which this resource is associated with. + Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. + maxLength: 253 + minLength: 1 + type: string + required: + - userRef type: object id: description: |- @@ -421,6 +463,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -461,38 +504,54 @@ spec: resource must be specified if the management policy is `managed`. properties: + accessRules: + description: accessRules is a list of fine grained access control + rules + items: + description: ApplicationCredentialAccessRule defines an access + rule + minProperties: 1 + properties: + method: + description: method that the application credential is permitted + to use for a given API endpoint + enum: + - CONNECT + - DELETE + - GET + - HEAD + - OPTIONS + - PATCH + - POST + - PUT + - TRACE + type: string + path: + description: path that the application credential is permitted + to access + maxLength: 1024 + type: string + serviceRef: + description: serviceRef identifier for the service that + the application credential is permitted to access + maxLength: 253 + minLength: 1 + type: string + type: object + maxItems: 256 + type: array + x-kubernetes-list-type: atomic description: - description: description contains a free form description of the - flavor. - maxLength: 65535 + description: description is a human-readable description for the + resource. + maxLength: 255 minLength: 1 type: string - disk: - description: |- - disk is the size of the root disk that will be created in GiB. If 0 - the root disk will be set to exactly the size of the image used to - deploy the instance. However, in this case the scheduler cannot - select the compute host based on the virtual image size. Therefore, - 0 should only be used for volume booted instances or for testing - purposes. Volume-backed instances can be enforced for flavors with - zero root disk via the - os_compute_api:servers:create:zero_disk_flavor policy rule. - format: int32 - minimum: 0 - type: integer - ephemeral: - description: |- - ephemeral is the size of the ephemeral disk that will be created, in GiB. - Ephemeral disks may be written over on server state changes. So should only - be used as a scratch space for applications that are aware of its - limitations. Defaults to 0. - format: int32 - minimum: 0 - type: integer - isPublic: - description: isPublic flags a flavor as being available to all - projects or not. - type: boolean + expiresAt: + description: expiresAt is the time of expiration for the application + credential. If unset, the application credential does not expire. + format: date-time + type: string name: description: |- name will be the name of the created resource. If not specified, the @@ -501,30 +560,42 @@ spec: minLength: 1 pattern: ^[^,]+$ type: string - ram: - description: ram is the memory of the flavor, measured in MB. - format: int32 - minimum: 1 - type: integer - swap: + roleRefs: + description: roleRefs may only contain roles that the user has + assigned on the project. If not provided, the roles assigned + to the application credential will be the same as the roles + in the current token. + items: + maxLength: 253 + minLength: 1 + type: string + maxItems: 256 + type: array + x-kubernetes-list-type: atomic + secretRef: + description: secretRef is a reference to a Secret containing the + application credential secret + maxLength: 253 + minLength: 1 + type: string + unrestricted: + description: unrestricted is a flag indicating whether the application + credential may be used for creation or destruction of other + application credentials or trusts + type: boolean + userRef: description: |- - swap is the size of a dedicated swap disk that will be allocated, in - MiB. If 0 (the default), no dedicated swap disk will be created. - format: int32 - minimum: 0 - type: integer - vcpus: - description: vcpus is the number of vcpus for the flavor. - format: int32 - minimum: 1 - type: integer + userRef is a reference to the ORC User which this resource is associated with. + Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. + maxLength: 253 + minLength: 1 + type: string required: - - disk - - ram - - vcpus + - secretRef + - userRef type: object x-kubernetes-validations: - - message: FlavorResourceSpec is immutable + - message: ApplicationCredentialResourceSpec is immutable rule: self == oldSelf required: - cloudCredentialsRef @@ -623,71 +694,112 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack resource. properties: + accessRules: + description: accessRules is a list of fine grained access control + rules + items: + properties: + id: + description: id is the ID of this access rule + maxLength: 1024 + type: string + method: + description: method that the application credential is permitted + to use for a given API endpoint + maxLength: 32 + type: string + path: + description: path that the application credential is permitted + to access + maxLength: 1024 + type: string + service: + description: service type identifier for the service that + the application credential is permitted to access + maxLength: 1024 + type: string + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic description: description: description is a human-readable description for the resource. - maxLength: 65535 + maxLength: 1024 + type: string + expiresAt: + description: expiresAt is the time of expiration for the application + credential. If unset, the application credential does not expire. + format: date-time type: string - disk: - description: disk is the size of the root disk that will be created - in GiB. - format: int32 - type: integer - ephemeral: - description: ephemeral is the size of the ephemeral disk, in GiB. - format: int32 - type: integer - isPublic: - description: isPublic flags a flavor as being available to all - projects or not. - type: boolean name: - description: name is a Human-readable name for the flavor. Might + description: name is a Human-readable name for the resource. Might not be unique. maxLength: 1024 type: string - ram: - description: ram is the memory of the flavor, measured in MB. - format: int32 - type: integer - swap: - description: |- - swap is the size of a dedicated swap disk that will be allocated, in - MiB. - format: int32 - type: integer - vcpus: - description: vcpus is the number of vcpus for the flavor. - format: int32 - type: integer - type: object - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 + projectID: + description: projectID of the project the application credential + was created for and that authentication requests using this + application credential will be scoped to. + maxLength: 1024 + type: string + roles: + description: roles is a list of role objects may only contain + roles that the user has assigned on the project + items: + properties: + domainID: + description: domainID of the domain of this role + maxLength: 1024 + type: string + id: + description: id is the ID of a role + maxLength: 1024 + type: string + name: + description: name of an existing role + maxLength: 1024 + type: string + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + unrestricted: + description: unrestricted is a flag indicating whether the application + credential may be used for creation or destruction of other + application credentials or trusts + type: boolean + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: floatingips.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: domains.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: FloatingIP - listKind: FloatingIPList - plural: floatingips - singular: floatingip + kind: Domain + listKind: DomainList + plural: domains + singular: domain scope: Namespaced versions: - additionalPrinterColumns: @@ -699,10 +811,6 @@ spec: jsonPath: .status.conditions[?(@.type=='Available')].status name: Available type: string - - description: Allocated IP address - jsonPath: .status.resource.floatingIP - name: Address - type: string - description: Message describing current progress status jsonPath: .status.conditions[?(@.type=='Progressing')].message name: Message @@ -710,7 +818,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: FloatingIP is the Schema for an ORC resource. + description: Domain is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -769,96 +877,16 @@ spec: error state and will not continue to retry. minProperties: 1 properties: - description: - description: description of the existing resource - maxLength: 255 - minLength: 1 - type: string - floatingIP: - description: floatingIP is the floatingip address. - maxLength: 45 - minLength: 1 - type: string - floatingNetworkRef: - description: floatingNetworkRef is a reference to the ORC - Network which this resource is associated with. - maxLength: 253 - minLength: 1 - type: string - notTags: - description: |- - notTags is a list of tags to filter by. If specified, resources which - contain all of the given tags will be excluded from the result. - items: - description: |- - NeutronTag represents a tag on a Neutron resource. - It may not be empty and may not contain commas. - maxLength: 255 - minLength: 1 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: set - notTagsAny: - description: |- - notTagsAny is a list of tags to filter by. If specified, resources - which contain any of the given tags will be excluded from the result. - items: - description: |- - NeutronTag represents a tag on a Neutron resource. - It may not be empty and may not contain commas. - maxLength: 255 - minLength: 1 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: set - portRef: - description: portRef is a reference to the ORC Port which - this resource is associated with. - maxLength: 253 - minLength: 1 - type: string - projectRef: + enabled: description: |- - projectRef is a reference to the ORC Project this resource is associated with. - Typically, only used by admin. - maxLength: 253 + enabled defines whether a domain is enabled or not. Default is true. + Note: Users can only authorize against an enabled domain (and any of its projects). + type: boolean + name: + description: name of the existing resource + maxLength: 64 minLength: 1 type: string - status: - description: status is the status of the floatingip. - maxLength: 1024 - type: string - tags: - description: |- - tags is a list of tags to filter by. If specified, the resource must - have all of the tags specified to be included in the result. - items: - description: |- - NeutronTag represents a tag on a Neutron resource. - It may not be empty and may not contain commas. - maxLength: 255 - minLength: 1 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: set - tagsAny: - description: |- - tagsAny is a list of tags to filter by. If specified, the resource - must have at least one of the tags specified to be included in the - result. - items: - description: |- - NeutronTag represents a tag on a Neutron resource. - It may not be empty and may not contain commas. - maxLength: 255 - minLength: 1 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: set type: object id: description: |- @@ -866,6 +894,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -912,80 +941,19 @@ spec: maxLength: 255 minLength: 1 type: string - fixedIP: - description: fixedIP is the IP address of the port to which the - floatingip is associated. - maxLength: 45 - minLength: 1 - type: string - x-kubernetes-validations: - - message: fixedIP is immutable - rule: self == oldSelf - floatingIP: + enabled: description: |- - floatingIP is the IP that will be assigned to the floatingip. If not set, it will - be assigned automatically. - maxLength: 45 - minLength: 1 - type: string - x-kubernetes-validations: - - message: floatingIP is immutable - rule: self == oldSelf - floatingNetworkRef: - description: floatingNetworkRef references the network to which - the floatingip is associated. - maxLength: 253 - minLength: 1 - type: string - x-kubernetes-validations: - - message: floatingNetworkRef is immutable - rule: self == oldSelf - floatingSubnetRef: - description: floatingSubnetRef references the subnet to which - the floatingip is associated. - maxLength: 253 - minLength: 1 - type: string - x-kubernetes-validations: - - message: floatingSubnetRef is immutable - rule: self == oldSelf - portRef: - description: portRef is a reference to the ORC Port which this - resource is associated with. - maxLength: 253 - minLength: 1 - type: string - x-kubernetes-validations: - - message: portRef is immutable - rule: self == oldSelf - projectRef: + enabled defines whether a domain is enabled or not. Default is true. + Note: Users can only authorize against an enabled domain (and any of its projects). + type: boolean + name: description: |- - projectRef is a reference to the ORC Project this resource is associated with. - Typically, only used by admin. - maxLength: 253 + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 64 minLength: 1 type: string - x-kubernetes-validations: - - message: projectRef is immutable - rule: self == oldSelf - tags: - description: tags is a list of tags which will be applied to the - floatingip. - items: - description: |- - NeutronTag represents a tag on a Neutron resource. - It may not be empty and may not contain commas. - maxLength: 255 - minLength: 1 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: set type: object - x-kubernetes-validations: - - message: Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' - must be set - rule: has(self.floatingNetworkRef) != has(self.floatingSubnetRef) required: - cloudCredentialsRef type: object @@ -1083,76 +1051,31 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack resource. properties: - createdAt: - description: createdAt shows the date and time when the resource - was created. The date and time stamp format is ISO 8601 - format: date-time - type: string description: description: description is a human-readable description for the resource. maxLength: 1024 type: string - fixedIP: - description: fixedIP is the IP address of the port to which the - floatingip is associated. - maxLength: 1024 - type: string - floatingIP: - description: floatingIP is the IP address of the floatingip. - maxLength: 1024 - type: string - floatingNetworkID: - description: floatingNetworkID is the ID of the network to which - the floatingip is associated. - maxLength: 1024 - type: string - portID: - description: portID is the ID of the port to which the floatingip - is associated. - maxLength: 1024 - type: string - projectID: - description: projectID is the project owner of the resource. + enabled: + description: |- + enabled defines whether a domain is enabled or not. Default is true. + Note: Users can only authorize against an enabled domain (and any of its projects). + type: boolean + name: + description: name is a Human-readable name for the resource. Might + not be unique. maxLength: 1024 type: string - revisionNumber: - description: revisionNumber optionally set via extensions/standard-attr-revisions - format: int64 - type: integer - routerID: - description: routerID is the ID of the router to which the floatingip - is associated. - maxLength: 1024 - type: string - status: - description: status indicates the current status of the resource. - maxLength: 1024 - type: string - tags: - description: tags is the list of tags on the resource. - items: - maxLength: 1024 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: atomic - tenantID: - description: tenantID is the project owner of the resource. - maxLength: 1024 - type: string - updatedAt: - description: updatedAt shows the date and time when the resource - was updated. The date and time stamp format is ISO 8601 - format: date-time - type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -1163,17 +1086,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: groups.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: endpoints.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: Group - listKind: GroupList - plural: groups - singular: group + kind: Endpoint + listKind: EndpointList + plural: endpoints + singular: endpoint scope: Namespaced versions: - additionalPrinterColumns: @@ -1192,7 +1115,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Group is the Schema for an ORC resource. + description: Endpoint is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -1251,16 +1174,22 @@ spec: error state and will not continue to retry. minProperties: 1 properties: - domainRef: - description: domainRef is a reference to the ORC Domain which - this resource is associated with. + interface: + description: interface of the existing endpoint. + enum: + - admin + - internal + - public + type: string + serviceRef: + description: serviceRef is a reference to the ORC Service + which this resource is associated with. maxLength: 253 minLength: 1 type: string - name: - description: name of the existing resource - maxLength: 64 - minLength: 1 + url: + description: url is the URL of the existing endpoint. + maxLength: 1024 type: string type: object id: @@ -1269,6 +1198,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -1315,22 +1245,37 @@ spec: maxLength: 255 minLength: 1 type: string - domainRef: - description: domainRef is a reference to the ORC Domain which + x-kubernetes-validations: + - message: description is immutable + rule: self == oldSelf + enabled: + description: enabled indicates whether the endpoint is enabled + or not. + type: boolean + interface: + description: interface indicates the visibility of the endpoint. + enum: + - admin + - internal + - public + type: string + serviceRef: + description: serviceRef is a reference to the ORC Service which this resource is associated with. maxLength: 253 minLength: 1 type: string x-kubernetes-validations: - - message: domainRef is immutable + - message: serviceRef is immutable rule: self == oldSelf - name: - description: |- - name will be the name of the created resource. If not specified, the - name of the ORC object will be used. - maxLength: 64 - minLength: 1 + url: + description: url is the endpoint URL. + maxLength: 1024 type: string + required: + - interface + - serviceRef + - url type: object required: - cloudCredentialsRef @@ -1429,6 +1374,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -1437,20 +1383,30 @@ spec: description: description: description is a human-readable description for the resource. - maxLength: 1024 + maxLength: 255 + minLength: 1 type: string - domainID: - description: domainID is the ID of the Domain to which the resource + enabled: + description: enabled indicates whether the endpoint is enabled + or not. + type: boolean + interface: + description: interface indicates the visibility of the endpoint. + maxLength: 128 + type: string + serviceID: + description: serviceID is the ID of the Service to which the resource is associated. maxLength: 1024 type: string - name: - description: name is a Human-readable name for the resource. Might - not be unique. + url: + description: url is the endpoint URL. maxLength: 1024 type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -1461,17 +1417,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: images.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: flavors.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: Image - listKind: ImageList - plural: images - singular: image + kind: Flavor + listKind: FlavorList + plural: flavors + singular: flavor scope: Namespaced versions: - additionalPrinterColumns: @@ -1490,7 +1446,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Image is the Schema for an ORC resource. + description: Flavor is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -1549,30 +1505,28 @@ spec: error state and will not continue to retry. minProperties: 1 properties: + disk: + description: disk is the size of the root disk in GiB. + format: int32 + minimum: 0 + type: integer name: - description: name specifies the name of a Glance image + description: name of the existing resource maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - tags: - description: tags is the list of tags on the resource. - items: - maxLength: 255 - minLength: 1 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: set - visibility: - description: visibility specifies the visibility of a Glance - image. - enum: - - public - - private - - shared - - community - type: string + ram: + description: ram is the memory of the flavor, measured in + MB. + format: int32 + minimum: 1 + type: integer + vcpus: + description: vcpus is the number of vcpus for the flavor. + format: int32 + minimum: 1 + type: integer type: object id: description: |- @@ -1580,6 +1534,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -1620,114 +1575,1285 @@ spec: resource must be specified if the management policy is `managed`. properties: - content: - description: content specifies how to obtain the image content. - properties: - containerFormat: - default: bare - description: |- - containerFormat is the format of the image container. - qcow2 and raw images do not usually have a container. This is specified as "bare", which is also the default. - Permitted values are ami, ari, aki, bare, compressed, ovf, ova, and docker. - enum: - - ami - - ari - - aki - - bare - - ovf - - ova - - docker - - compressed - type: string - diskFormat: - description: |- - diskFormat is the format of the disk image. - Normal values are "qcow2", or "raw". Glance may be configured to support others. - enum: - - ami - - ari - - aki - - vhd - - vhdx - - vmdk - - raw - - qcow2 - - vdi - - ploop - - iso - type: string - download: - description: |- - download describes how to obtain image data by downloading it from a URL. - Must be set when creating a managed image. - properties: - decompress: - description: |- - decompress specifies that the source data must be decompressed with the - given compression algorithm before being stored. Specifying Decompress - will disable the use of Glance's web-download, as web-download cannot - currently deterministically decompress downloaded content. - enum: - - xz - - gz - - bz2 - type: string - hash: - description: |- - hash is a hash which will be used to verify downloaded data, i.e. - before any decompression. If not specified, no hash verification will be - performed. Specifying a Hash will disable the use of Glance's - web-download, as web-download cannot currently deterministically verify - the hash of downloaded content. - properties: - algorithm: - description: algorithm is the hash algorithm used - to generate value. - enum: - - md5 - - sha1 - - sha256 - - sha512 - type: string - value: - description: value is the hash of the image data using - Algorithm. It must be hex encoded using lowercase - letters. - maxLength: 1024 - minLength: 1 - pattern: ^[0-9a-f]+$ - type: string - required: - - algorithm - - value - type: object - x-kubernetes-validations: - - message: hash is immutable - rule: self == oldSelf - url: - description: url containing image data - format: uri - maxLength: 2048 - type: string - required: - - url - type: object - required: - - diskFormat - - download - type: object - x-kubernetes-validations: - - message: content is immutable - rule: self == oldSelf + description: + description: description contains a free form description of the + flavor. + maxLength: 65535 + minLength: 1 + type: string + disk: + description: |- + disk is the size of the root disk that will be created in GiB. If 0 + the root disk will be set to exactly the size of the image used to + deploy the instance. However, in this case the scheduler cannot + select the compute host based on the virtual image size. Therefore, + 0 should only be used for volume booted instances or for testing + purposes. Volume-backed instances can be enforced for flavors with + zero root disk via the + os_compute_api:servers:create:zero_disk_flavor policy rule. + format: int32 + minimum: 0 + type: integer + ephemeral: + description: |- + ephemeral is the size of the ephemeral disk that will be created, in GiB. + Ephemeral disks may be written over on server state changes. So should only + be used as a scratch space for applications that are aware of its + limitations. Defaults to 0. + format: int32 + minimum: 0 + type: integer + isPublic: + description: isPublic flags a flavor as being available to all + projects or not. + type: boolean name: description: |- - name will be the name of the created Glance image. If not specified, the - name of the Image object will be used. + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - properties: + ram: + description: ram is the memory of the flavor, measured in MB. + format: int32 + minimum: 1 + type: integer + swap: + description: |- + swap is the size of a dedicated swap disk that will be allocated, in + MiB. If 0 (the default), no dedicated swap disk will be created. + format: int32 + minimum: 0 + type: integer + vcpus: + description: vcpus is the number of vcpus for the flavor. + format: int32 + minimum: 1 + type: integer + required: + - disk + - ram + - vcpus + type: object + x-kubernetes-validations: + - message: FlavorResourceSpec is immutable + rule: self == oldSelf + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 65535 + type: string + disk: + description: disk is the size of the root disk that will be created + in GiB. + format: int32 + type: integer + ephemeral: + description: ephemeral is the size of the ephemeral disk, in GiB. + format: int32 + type: integer + isPublic: + description: isPublic flags a flavor as being available to all + projects or not. + type: boolean + name: + description: name is a Human-readable name for the flavor. Might + not be unique. + maxLength: 1024 + type: string + ram: + description: ram is the memory of the flavor, measured in MB. + format: int32 + type: integer + swap: + description: |- + swap is the size of a dedicated swap disk that will be allocated, in + MiB. + format: int32 + type: integer + vcpus: + description: vcpus is the number of vcpus for the flavor. + format: int32 + type: integer + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: floatingips.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: FloatingIP + listKind: FloatingIPList + plural: floatingips + singular: floatingip + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Allocated IP address + jsonPath: .status.resource.floatingIP + name: Address + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: FloatingIP is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + description: + description: description of the existing resource + maxLength: 255 + minLength: 1 + type: string + floatingIP: + description: floatingIP is the floatingip address. + maxLength: 45 + minLength: 1 + type: string + floatingNetworkRef: + description: floatingNetworkRef is a reference to the ORC + Network which this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + notTags: + description: |- + notTags is a list of tags to filter by. If specified, resources which + contain all of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + notTagsAny: + description: |- + notTagsAny is a list of tags to filter by. If specified, resources + which contain any of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + portRef: + description: portRef is a reference to the ORC Port which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + projectRef: + description: |- + projectRef is a reference to the ORC Project this resource is associated with. + Typically, only used by admin. + maxLength: 253 + minLength: 1 + type: string + status: + description: status is the status of the floatingip. + maxLength: 1024 + type: string + tags: + description: |- + tags is a list of tags to filter by. If specified, the resource must + have all of the tags specified to be included in the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + tagsAny: + description: |- + tagsAny is a list of tags to filter by. If specified, the resource + must have at least one of the tags specified to be included in the + result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + fixedIP: + description: fixedIP is the IP address of the port to which the + floatingip is associated. + maxLength: 45 + minLength: 1 + type: string + x-kubernetes-validations: + - message: fixedIP is immutable + rule: self == oldSelf + floatingIP: + description: |- + floatingIP is the IP that will be assigned to the floatingip. If not set, it will + be assigned automatically. + maxLength: 45 + minLength: 1 + type: string + x-kubernetes-validations: + - message: floatingIP is immutable + rule: self == oldSelf + floatingNetworkRef: + description: floatingNetworkRef references the network to which + the floatingip is associated. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: floatingNetworkRef is immutable + rule: self == oldSelf + floatingSubnetRef: + description: floatingSubnetRef references the subnet to which + the floatingip is associated. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: floatingSubnetRef is immutable + rule: self == oldSelf + portRef: + description: portRef is a reference to the ORC Port which this + resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: portRef is immutable + rule: self == oldSelf + projectRef: + description: |- + projectRef is a reference to the ORC Project this resource is associated with. + Typically, only used by admin. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: projectRef is immutable + rule: self == oldSelf + tags: + description: tags is a list of tags which will be applied to the + floatingip. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + type: object + x-kubernetes-validations: + - message: Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' + must be set + rule: has(self.floatingNetworkRef) != has(self.floatingSubnetRef) + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + createdAt: + description: createdAt shows the date and time when the resource + was created. The date and time stamp format is ISO 8601 + format: date-time + type: string + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + fixedIP: + description: fixedIP is the IP address of the port to which the + floatingip is associated. + maxLength: 1024 + type: string + floatingIP: + description: floatingIP is the IP address of the floatingip. + maxLength: 1024 + type: string + floatingNetworkID: + description: floatingNetworkID is the ID of the network to which + the floatingip is associated. + maxLength: 1024 + type: string + portID: + description: portID is the ID of the port to which the floatingip + is associated. + maxLength: 1024 + type: string + projectID: + description: projectID is the project owner of the resource. + maxLength: 1024 + type: string + revisionNumber: + description: revisionNumber optionally set via extensions/standard-attr-revisions + format: int64 + type: integer + routerID: + description: routerID is the ID of the router to which the floatingip + is associated. + maxLength: 1024 + type: string + status: + description: status indicates the current status of the resource. + maxLength: 1024 + type: string + tags: + description: tags is the list of tags on the resource. + items: + maxLength: 1024 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + tenantID: + description: tenantID is the project owner of the resource. + maxLength: 1024 + type: string + updatedAt: + description: updatedAt shows the date and time when the resource + was updated. The date and time stamp format is ISO 8601 + format: date-time + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: groups.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: Group + listKind: GroupList + plural: groups + singular: group + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Group is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + name: + description: name of the existing resource + maxLength: 64 + minLength: 1 + type: string + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: domainRef is immutable + rule: self == oldSelf + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 64 + minLength: 1 + type: string + type: object + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + domainID: + description: domainID is the ID of the Domain to which the resource + is associated. + maxLength: 1024 + type: string + name: + description: name is a Human-readable name for the resource. Might + not be unique. + maxLength: 1024 + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: images.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: Image + listKind: ImageList + plural: images + singular: image + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Image is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + name: + description: name specifies the name of a Glance image + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + tags: + description: tags is the list of tags on the resource. + items: + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + visibility: + description: visibility specifies the visibility of a Glance + image. + enum: + - public + - private + - shared + - community + type: string + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + content: + description: content specifies how to obtain the image content. + properties: + containerFormat: + default: bare + description: |- + containerFormat is the format of the image container. + qcow2 and raw images do not usually have a container. This is specified as "bare", which is also the default. + Permitted values are ami, ari, aki, bare, compressed, ovf, ova, and docker. + enum: + - ami + - ari + - aki + - bare + - ovf + - ova + - docker + - compressed + type: string + diskFormat: + description: |- + diskFormat is the format of the disk image. + Normal values are "qcow2", or "raw". Glance may be configured to support others. + enum: + - ami + - ari + - aki + - vhd + - vhdx + - vmdk + - raw + - qcow2 + - vdi + - ploop + - iso + type: string + download: + description: |- + download describes how to obtain image data by downloading it from a URL. + Must be set when creating a managed image. + properties: + decompress: + description: |- + decompress specifies that the source data must be decompressed with the + given compression algorithm before being stored. Specifying Decompress + will disable the use of Glance's web-download, as web-download cannot + currently deterministically decompress downloaded content. + enum: + - xz + - gz + - bz2 + type: string + hash: + description: |- + hash is a hash which will be used to verify downloaded data, i.e. + before any decompression. If not specified, no hash verification will be + performed. Specifying a Hash will disable the use of Glance's + web-download, as web-download cannot currently deterministically verify + the hash of downloaded content. + properties: + algorithm: + description: algorithm is the hash algorithm used + to generate value. + enum: + - md5 + - sha1 + - sha256 + - sha512 + type: string + value: + description: value is the hash of the image data using + Algorithm. It must be hex encoded using lowercase + letters. + maxLength: 1024 + minLength: 1 + pattern: ^[0-9a-f]+$ + type: string + required: + - algorithm + - value + type: object + x-kubernetes-validations: + - message: hash is immutable + rule: self == oldSelf + url: + description: url containing image data + format: uri + maxLength: 2048 + type: string + required: + - url + type: object + required: + - diskFormat + - download + type: object + x-kubernetes-validations: + - message: content is immutable + rule: self == oldSelf + name: + description: |- + name will be the name of the created Glance image. If not specified, the + name of the Image object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + properties: description: properties is metadata available to consumers of the image properties: @@ -2102,6 +3228,7 @@ spec: type: integer id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -2171,6 +3298,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -2181,7 +3310,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: keypairs.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -2282,6 +3411,7 @@ spec: the resource name as the unique identifier, not a UUID. When specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. + maxLength: 1024 type: string type: object managedOptions: @@ -2443,6 +3573,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -2467,6 +3598,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -2477,7 +3610,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: networks.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -2652,6 +3785,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -2880,6 +4014,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -3014,6 +4149,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -3024,7 +4161,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: ports.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -3116,11 +4253,20 @@ spec: error state and will not continue to retry. minProperties: 1 properties: + adminStateUp: + description: |- + adminStateUp is the administrative state of the port, + which is up (true) or down (false). + type: boolean description: description: description of the existing resource maxLength: 255 minLength: 1 type: string + macAddress: + description: macAddress is the MAC address of the port. + maxLength: 32 + type: string name: description: name of the existing resource maxLength: 255 @@ -3204,6 +4350,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -3272,6 +4419,12 @@ spec: x-kubernetes-validations: - message: addresses is immutable rule: self == oldSelf + adminStateUp: + default: true + description: |- + adminStateUp is the administrative state of the port, + which is up (true) or down (false). The default value is true. + type: boolean allowedAddressPairs: description: allowedAddressPairs are allowed addresses associated with this port. @@ -3304,6 +4457,43 @@ spec: maxLength: 255 minLength: 1 type: string + hostID: + description: |- + hostID specifies the host where the port will be bound. + Note that when the port is attached to a server, OpenStack may + rebind the port to the server's actual compute host, which may + differ from the specified hostID if no matching scheduler hint + is used. In this case the port's status will reflect the actual + binding host, not the value specified here. + maxProperties: 1 + minProperties: 1 + properties: + id: + description: |- + id is the literal host ID string to use for binding:host_id. + This is mutually exclusive with serverRef. + maxLength: 36 + type: string + serverRef: + description: |- + serverRef is a reference to an ORC Server resource from which to + retrieve the hostID for port binding. The hostID will be read from + the Server's status.resource.hostID field. + This is mutually exclusive with id. + maxLength: 253 + minLength: 1 + type: string + type: object + x-kubernetes-validations: + - message: hostID is immutable + rule: self == oldSelf + - message: exactly one of id or serverRef must be set + rule: (has(self.id) && size(self.id) > 0) != (has(self.serverRef) + && size(self.serverRef) > 0) + macAddress: + description: macAddress is the MAC address of the port. + maxLength: 32 + type: string name: description: name is a human-readable name of the port. If not set, the object's name will be used. @@ -3491,6 +4681,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -3563,6 +4754,10 @@ spec: maxItems: 128 type: array x-kubernetes-list-type: atomic + hostID: + description: hostID is the ID of host where the port resides. + maxLength: 128 + type: string macAddress: description: macAddress is the MAC address of the port. maxLength: 1024 @@ -3626,6 +4821,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -3636,7 +4833,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: projects.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -3724,6 +4921,12 @@ spec: error state and will not continue to retry. minProperties: 1 properties: + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string name: description: name of the existing resource maxLength: 64 @@ -3781,6 +4984,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -3827,6 +5031,15 @@ spec: maxLength: 65535 minLength: 1 type: string + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: domainRef is immutable + rule: self == oldSelf enabled: description: enabled defines whether a project is enabled or not. Default is true. @@ -3947,6 +5160,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -3957,6 +5171,11 @@ spec: resource. maxLength: 65535 type: string + domainID: + description: domainID is the ID of the Domain to which the resource + is associated. + maxLength: 1024 + type: string enabled: description: enabled represents whether a project is enabled or not. @@ -3976,6 +5195,8 @@ spec: x-kubernetes-list-type: atomic type: object type: object + required: + - spec type: object served: true storage: true @@ -3986,7 +5207,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: roles.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -4092,6 +5313,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -4252,6 +5474,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -4274,6 +5497,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -4284,7 +5509,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: routerinterfaces.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -4443,6 +5668,8 @@ spec: maxLength: 1024 type: string type: object + required: + - spec type: object served: true storage: true @@ -4453,7 +5680,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: routers.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -4623,6 +5850,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -4846,6 +6074,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -4908,6 +6137,8 @@ spec: x-kubernetes-list-type: atomic type: object type: object + required: + - spec type: object served: true storage: true @@ -4918,7 +6149,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: securitygroups.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -5088,6 +6319,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -5117,69 +6349,329 @@ spec: - managed - unmanaged type: string - x-kubernetes-validations: - - message: managementPolicy is immutable - rule: self == oldSelf + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + projectRef: + description: |- + projectRef is a reference to the ORC Project this resource is associated with. + Typically, only used by admin. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: projectRef is immutable + rule: self == oldSelf + rules: + description: rules is a list of security group rules belonging + to this SG. + items: + description: SecurityGroupRule defines a Security Group rule + minProperties: 1 + properties: + description: + description: description is a human-readable description + for the resource. + maxLength: 255 + minLength: 1 + type: string + direction: + description: |- + direction represents the direction in which the security group rule + is applied. Can be ingress or egress. + enum: + - ingress + - egress + type: string + ethertype: + description: |- + ethertype must be IPv4 or IPv6, and addresses represented in CIDR + must match the ingress or egress rules. + enum: + - IPv4 + - IPv6 + type: string + portRange: + description: |- + portRange sets the minimum and maximum ports range that the security group rule + matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than + or equal to the PortRange.Max attribute value. + If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max + should be an ICMP type + properties: + max: + description: |- + max is the maximum port number in the range that is matched by the security group rule. + If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal + to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code. + format: int32 + maximum: 65535 + minimum: 0 + type: integer + min: + description: |- + min is the minimum port number in the range that is matched by the security group rule. + If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal + to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type + format: int32 + maximum: 65535 + minimum: 0 + type: integer + required: + - max + - min + type: object + protocol: + description: protocol is the IP protocol is represented + by a string + enum: + - ah + - dccp + - egp + - esp + - gre + - icmp + - icmpv6 + - igmp + - ipip + - ipv6-encap + - ipv6-frag + - ipv6-icmp + - ipv6-nonxt + - ipv6-opts + - ipv6-route + - ospf + - pgm + - rsvp + - sctp + - tcp + - udp + - udplite + - vrrp + type: string + remoteIPPrefix: + description: remoteIPPrefix is an IP address block. Should + match the Ethertype (IPv4 or IPv6) + format: cidr + maxLength: 49 + minLength: 1 + type: string + required: + - ethertype + type: object + x-kubernetes-validations: + - message: portRangeMax should be equal or greater than portRange.min + rule: (!has(self.portRange)|| !(self.protocol == 'tcp'|| self.protocol + == 'udp' || self.protocol == 'dccp' || self.protocol == + 'sctp' || self.protocol == 'udplite') || (self.portRange.min + <= self.portRange.max)) + - message: When protocol is ICMP or ICMPv6 portRange.min should + be between 0 and 255 + rule: '!(self.protocol == ''icmp'' || self.protocol == ''icmpv6'') + || !has(self.portRange)|| (self.portRange.min >= 0 && self.portRange.min + <= 255)' + - message: When protocol is ICMP or ICMPv6 portRange.max should + be between 0 and 255 + rule: '!(self.protocol == ''icmp'' || self.protocol == ''icmpv6'') + || !has(self.portRange)|| (self.portRange.max >= 0 && self.portRange.max + <= 255)' + maxItems: 256 + type: array + x-kubernetes-list-type: atomic + stateful: + description: stateful indicates if the security group is stateful + or stateless. + type: boolean + x-kubernetes-validations: + - message: stateful is immutable + rule: self == oldSelf + tags: + description: tags is a list of tags which will be applied to the + security group. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + type: object + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string resource: - description: |- - resource specifies the desired state of the resource. - - resource may not be specified if the management policy is `unmanaged`. - - resource must be specified if the management policy is `managed`. + description: resource contains the observed state of the OpenStack + resource. properties: + createdAt: + description: createdAt shows the date and time when the resource + was created. The date and time stamp format is ISO 8601 + format: date-time + type: string description: description: description is a human-readable description for the resource. - maxLength: 255 - minLength: 1 + maxLength: 1024 type: string name: - description: |- - name will be the name of the created resource. If not specified, the - name of the ORC object will be used. - maxLength: 255 - minLength: 1 - pattern: ^[^,]+$ + description: name is a Human-readable name for the security group. + Might not be unique. + maxLength: 1024 type: string - projectRef: - description: |- - projectRef is a reference to the ORC Project this resource is associated with. - Typically, only used by admin. - maxLength: 253 - minLength: 1 + projectID: + description: projectID is the project owner of the security group. + maxLength: 1024 type: string - x-kubernetes-validations: - - message: projectRef is immutable - rule: self == oldSelf + revisionNumber: + description: revisionNumber optionally set via extensions/standard-attr-revisions + format: int64 + type: integer rules: description: rules is a list of security group rules belonging to this SG. items: - description: SecurityGroupRule defines a Security Group rule - minProperties: 1 properties: description: description: description is a human-readable description for the resource. - maxLength: 255 - minLength: 1 + maxLength: 1024 type: string direction: description: |- direction represents the direction in which the security group rule is applied. Can be ingress or egress. - enum: - - ingress - - egress + maxLength: 1024 type: string ethertype: description: |- ethertype must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules. - enum: - - IPv4 - - IPv6 + maxLength: 1024 + type: string + id: + description: id is the ID of the security group rule. + maxLength: 1024 type: string portRange: description: |- @@ -5195,8 +6687,6 @@ spec: If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code. format: int32 - maximum: 65535 - minimum: 0 type: integer min: description: |- @@ -5204,67 +6694,26 @@ spec: If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type format: int32 - maximum: 65535 - minimum: 0 type: integer - required: - - max - - min type: object protocol: - description: protocol is the IP protocol is represented - by a string - enum: - - ah - - dccp - - egp - - esp - - gre - - icmp - - icmpv6 - - igmp - - ipip - - ipv6-encap - - ipv6-frag - - ipv6-icmp - - ipv6-nonxt - - ipv6-opts - - ipv6-route - - ospf - - pgm - - rsvp - - sctp - - tcp - - udp - - udplite - - vrrp + description: |- + protocol is the IP protocol can be represented by a string, an + integer, or null + maxLength: 1024 + type: string + remoteGroupID: + description: |- + remoteGroupID is the remote group UUID to associate with this security group rule + RemoteGroupID + maxLength: 1024 type: string remoteIPPrefix: description: remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6) - format: cidr - maxLength: 49 - minLength: 1 + maxLength: 1024 type: string - required: - - ethertype type: object - x-kubernetes-validations: - - message: portRangeMax should be equal or greater than portRange.min - rule: (!has(self.portRange)|| !(self.protocol == 'tcp'|| self.protocol - == 'udp' || self.protocol == 'dccp' || self.protocol == - 'sctp' || self.protocol == 'udplite') || (self.portRange.min - <= self.portRange.max)) - - message: When protocol is ICMP or ICMPv6 portRange.min should - be between 0 and 255 - rule: '!(self.protocol == ''icmp'' || self.protocol == ''icmpv6'') - || !has(self.portRange)|| (self.portRange.min >= 0 && self.portRange.min - <= 255)' - - message: When protocol is ICMP or ICMPv6 portRange.max should - be between 0 and 255 - rule: '!(self.protocol == ''icmp'' || self.protocol == ''icmpv6'') - || !has(self.portRange)|| (self.portRange.max >= 0 && self.portRange.max - <= 255)' maxItems: 256 type: array x-kubernetes-list-type: atomic @@ -5272,23 +6721,211 @@ spec: description: stateful indicates if the security group is stateful or stateless. type: boolean - x-kubernetes-validations: - - message: stateful is immutable - rule: self == oldSelf tags: - description: tags is a list of tags which will be applied to the - security group. + description: tags is the list of tags on the resource. items: - description: |- - NeutronTag represents a tag on a Neutron resource. - It may not be empty and may not contain commas. - maxLength: 255 - minLength: 1 + maxLength: 1024 type: string maxItems: 64 type: array - x-kubernetes-list-type: set + x-kubernetes-list-type: atomic + updatedAt: + description: updatedAt shows the date and time when the resource + was updated. The date and time stamp format is ISO 8601 + format: date-time + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: servergroups.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: ServerGroup + listKind: ServerGroupList + plural: servergroups + singular: servergroup + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ServerGroup is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + policy: + description: policy is the policy to use for the server group. + enum: + - affinity + - anti-affinity + - soft-affinity + - soft-anti-affinity + type: string + rules: + description: rules is the rules to use for the server group. + properties: + maxServerPerHost: + description: |- + maxServerPerHost specifies how many servers can reside on a single compute host. + It can be used only with the "anti-affinity" policy. + format: int32 + type: integer + type: object + required: + - policy type: object + x-kubernetes-validations: + - message: ServerGroupResourceSpec is immutable + rule: self == oldSelf + - message: maxServerPerHost can only be used with the anti-affinity + policy + rule: 'has(self.rules) && self.rules.maxServerPerHost > 0 ? self.policy + == ''anti-affinity'' : true' required: - cloudCredentialsRef type: object @@ -5374,135 +7011,55 @@ spec: type: string required: - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 32 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - id: - description: id is the unique identifier of the OpenStack resource. - type: string - resource: - description: resource contains the observed state of the OpenStack - resource. - properties: - createdAt: - description: createdAt shows the date and time when the resource - was created. The date and time stamp format is ISO 8601 - format: date-time - type: string - description: - description: description is a human-readable description for the - resource. - maxLength: 1024 - type: string - name: - description: name is a Human-readable name for the security group. - Might not be unique. - maxLength: 1024 - type: string - projectID: - description: projectID is the project owner of the security group. - maxLength: 1024 - type: string - revisionNumber: - description: revisionNumber optionally set via extensions/standard-attr-revisions - format: int64 - type: integer - rules: - description: rules is a list of security group rules belonging - to this SG. - items: - properties: - description: - description: description is a human-readable description - for the resource. - maxLength: 1024 - type: string - direction: - description: |- - direction represents the direction in which the security group rule - is applied. Can be ingress or egress. - maxLength: 1024 - type: string - ethertype: - description: |- - ethertype must be IPv4 or IPv6, and addresses represented in CIDR - must match the ingress or egress rules. - maxLength: 1024 - type: string - id: - description: id is the ID of the security group rule. - maxLength: 1024 - type: string - portRange: - description: |- - portRange sets the minimum and maximum ports range that the security group rule - matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than - or equal to the PortRange.Max attribute value. - If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max - should be an ICMP type - properties: - max: - description: |- - max is the maximum port number in the range that is matched by the security group rule. - If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal - to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code. - format: int32 - type: integer - min: - description: |- - min is the minimum port number in the range that is matched by the security group rule. - If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal - to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type - format: int32 - type: integer - type: object - protocol: - description: |- - protocol is the IP protocol can be represented by a string, an - integer, or null - maxLength: 1024 - type: string - remoteGroupID: - description: |- - remoteGroupID is the remote group UUID to associate with this security group rule - RemoteGroupID - maxLength: 1024 - type: string - remoteIPPrefix: - description: remoteIPPrefix is an IP address block. Should - match the Ethertype (IPv4 or IPv6) - maxLength: 1024 - type: string - type: object - maxItems: 256 - type: array - x-kubernetes-list-type: atomic - stateful: - description: stateful indicates if the security group is stateful - or stateless. - type: boolean - tags: - description: tags is the list of tags on the resource. - items: - maxLength: 1024 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: atomic - updatedAt: - description: updatedAt shows the date and time when the resource - was updated. The date and time stamp format is ISO 8601 - format: date-time + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + name: + description: name is a Human-readable name for the servergroup. + Might not be unique. + maxLength: 1024 + type: string + policy: + description: policy is the policy of the servergroup. + maxLength: 1024 + type: string + projectID: + description: projectID is the project owner of the resource. + maxLength: 1024 + type: string + rules: + description: rules is the rules of the server group. + properties: + maxServerPerHost: + description: |- + maxServerPerHost specifies how many servers can reside on a single compute host. + It can be used only with the "anti-affinity" policy. + format: int32 + type: integer + type: object + userID: + description: userID of the server group. + maxLength: 1024 type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -5513,17 +7070,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: servergroups.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: servers.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: ServerGroup - listKind: ServerGroupList - plural: servergroups - singular: servergroup + kind: Server + listKind: ServerList + plural: servers + singular: server scope: Namespaced versions: - additionalPrinterColumns: @@ -5542,7 +7099,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: ServerGroup is the Schema for an ORC resource. + description: Server is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -5601,12 +7158,62 @@ spec: error state and will not continue to retry. minProperties: 1 properties: + availabilityZone: + description: availabilityZone is the availability zone of + the existing resource + maxLength: 255 + type: string name: description: name of the existing resource maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string + notTags: + description: |- + notTags is a list of tags to filter by. If specified, resources which + contain all of the given tags will be excluded from the result. + items: + maxLength: 80 + minLength: 1 + type: string + maxItems: 50 + type: array + x-kubernetes-list-type: set + notTagsAny: + description: |- + notTagsAny is a list of tags to filter by. If specified, resources + which contain any of the given tags will be excluded from the result. + items: + maxLength: 80 + minLength: 1 + type: string + maxItems: 50 + type: array + x-kubernetes-list-type: set + tags: + description: |- + tags is a list of tags to filter by. If specified, the resource must + have all of the tags specified to be included in the result. + items: + maxLength: 80 + minLength: 1 + type: string + maxItems: 50 + type: array + x-kubernetes-list-type: set + tagsAny: + description: |- + tagsAny is a list of tags to filter by. If specified, the resource + must have at least one of the tags specified to be included in the + result. + items: + maxLength: 80 + minLength: 1 + type: string + maxItems: 50 + type: array + x-kubernetes-list-type: set type: object id: description: |- @@ -5614,6 +7221,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -5654,6 +7262,76 @@ spec: resource must be specified if the management policy is `managed`. properties: + availabilityZone: + description: availabilityZone is the availability zone in which + to create the server. + maxLength: 255 + type: string + x-kubernetes-validations: + - message: availabilityZone is immutable + rule: self == oldSelf + configDrive: + description: |- + configDrive specifies whether to attach a config drive to the server. + When true, configuration data will be available via a special drive + instead of the metadata service. + type: boolean + x-kubernetes-validations: + - message: configDrive is immutable + rule: self == oldSelf + flavorRef: + description: flavorRef references the flavor to use for the server + instance. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: flavorRef is immutable + rule: self == oldSelf + imageRef: + description: |- + imageRef references the image to use for the server instance. + NOTE: This is not required in case of boot from volume. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: imageRef is immutable + rule: self == oldSelf + keypairRef: + description: |- + keypairRef is a reference to a KeyPair object. The server will be + created with this keypair for SSH access. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: keypairRef is immutable + rule: self == oldSelf + metadata: + description: metadata is a list of metadata key-value pairs which + will be set on the server. + items: + description: ServerMetadata represents a key-value pair for + server metadata. + properties: + key: + description: key is the metadata key. + maxLength: 255 + minLength: 1 + type: string + value: + description: value is the metadata value. + maxLength: 255 + minLength: 1 + type: string + required: + - key + - value + type: object + maxItems: 128 + type: array + x-kubernetes-list-type: atomic name: description: |- name will be the name of the created resource. If not specified, the @@ -5662,34 +7340,91 @@ spec: minLength: 1 pattern: ^[^,]+$ type: string - policy: - description: policy is the policy to use for the server group. - enum: - - affinity - - anti-affinity - - soft-affinity - - soft-anti-affinity + ports: + description: ports defines a list of ports which will be attached + to the server. + items: + maxProperties: 1 + minProperties: 1 + properties: + portRef: + description: |- + portRef is a reference to a Port object. Server creation will wait for + this port to be created and available. + maxLength: 253 + minLength: 1 + type: string + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + serverGroupRef: + description: |- + serverGroupRef is a reference to a ServerGroup object. The server + will be created in the server group. + maxLength: 253 + minLength: 1 type: string - rules: - description: rules is the rules to use for the server group. + x-kubernetes-validations: + - message: serverGroupRef is immutable + rule: self == oldSelf + tags: + description: tags is a list of tags which will be applied to the + server. + items: + maxLength: 80 + minLength: 1 + type: string + maxItems: 50 + type: array + x-kubernetes-list-type: set + userData: + description: |- + userData specifies data which will be made available to the server at + boot time, either via the metadata service or a config drive. It is + typically read by a configuration service such as cloud-init or ignition. + maxProperties: 1 + minProperties: 1 properties: - maxServerPerHost: - description: |- - maxServerPerHost specifies how many servers can reside on a single compute host. - It can be used only with the "anti-affinity" policy. - format: int32 - type: integer + secretRef: + description: secretRef is a reference to a Secret containing + the user data for this server. + maxLength: 253 + minLength: 1 + type: string type: object + x-kubernetes-validations: + - message: userData is immutable + rule: self == oldSelf + volumes: + description: volumes is a list of volumes attached to the server. + items: + minProperties: 1 + properties: + device: + description: |- + device is the name of the device, such as `/dev/vdb`. + Omit for auto-assignment + maxLength: 255 + type: string + volumeRef: + description: |- + volumeRef is a reference to a Volume object. Server creation will wait for + this volume to be created and available. + maxLength: 253 + minLength: 1 + type: string + required: + - volumeRef + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic required: - - policy + - flavorRef + - imageRef + - ports type: object - x-kubernetes-validations: - - message: ServerGroupResourceSpec is immutable - rule: self == oldSelf - - message: maxServerPerHost can only be used with the anti-affinity - policy - rule: 'has(self.rules) && self.rules.maxServerPerHost > 0 ? self.policy - == ''anti-affinity'' : true' required: - cloudCredentialsRef type: object @@ -5787,40 +7522,143 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack resource. properties: - name: - description: name is a Human-readable name for the servergroup. - Might not be unique. + availabilityZone: + description: availabilityZone is the availability zone where the + server is located. maxLength: 1024 type: string - policy: - description: policy is the policy of the servergroup. + configDrive: + description: configDrive indicates whether the server was booted + with a config drive. + type: boolean + hostID: + description: hostID is the host where the server is located in + the cloud. maxLength: 1024 type: string - projectID: - description: projectID is the project owner of the resource. + imageID: + description: imageID indicates the OS image used to deploy the + server. maxLength: 1024 type: string - rules: - description: rules is the rules of the server group. - properties: - maxServerPerHost: - description: |- - maxServerPerHost specifies how many servers can reside on a single compute host. - It can be used only with the "anti-affinity" policy. - format: int32 - type: integer - type: object - userID: - description: userID of the server group. + interfaces: + description: interfaces contains the list of interfaces attached + to the server. + items: + properties: + fixedIPs: + description: fixedIPs is the list of fixed IP addresses + assigned to the interface. + items: + properties: + ipAddress: + description: ipAddress is the IP address assigned + to the port. + maxLength: 1024 + type: string + subnetID: + description: subnetID is the ID of the subnet from + which the IP address is allocated. + maxLength: 1024 + type: string + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + macAddr: + description: macAddr is the MAC address of the interface. + maxLength: 1024 + type: string + netID: + description: netID is the ID of the network to which the + interface is attached. + maxLength: 1024 + type: string + portID: + description: portID is the ID of a port attached to the + server. + maxLength: 1024 + type: string + portState: + description: portState is the state of the port (e.g., ACTIVE, + DOWN). + maxLength: 1024 + type: string + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + metadata: + description: metadata is the list of metadata key-value pairs + on the resource. + items: + description: ServerMetadataStatus represents a key-value pair + for server metadata in status. + properties: + key: + description: key is the metadata key. + maxLength: 255 + type: string + value: + description: value is the metadata value. + maxLength: 255 + type: string + type: object + maxItems: 128 + type: array + x-kubernetes-list-type: atomic + name: + description: name is the human-readable name of the resource. + Might not be unique. + maxLength: 1024 + type: string + serverGroups: + description: |- + serverGroups is a slice of strings containing the UUIDs of the + server groups to which the server belongs. Currently this can + contain at most one entry. + items: + maxLength: 1024 + type: string + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + status: + description: |- + status contains the current operational status of the server, + such as IN_PROGRESS or ACTIVE. maxLength: 1024 type: string + tags: + description: tags is the list of tags on the resource. + items: + maxLength: 1024 + type: string + maxItems: 50 + type: array + x-kubernetes-list-type: atomic + volumes: + description: volumes contains the volumes attached to the server. + items: + properties: + id: + description: id is the ID of a volume attached to the server. + maxLength: 1024 + type: string + type: object + maxItems: 64 + type: array + x-kubernetes-list-type: atomic type: object type: object + required: + - spec type: object served: true storage: true @@ -5831,17 +7669,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: servers.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: services.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: Server - listKind: ServerList - plural: servers - singular: server + kind: Service + listKind: ServiceList + plural: services + singular: service scope: Namespaced versions: - additionalPrinterColumns: @@ -5860,7 +7698,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Server is the Schema for an ORC resource. + description: Service is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -5919,62 +7757,17 @@ spec: error state and will not continue to retry. minProperties: 1 properties: - availabilityZone: - description: availabilityZone is the availability zone of - the existing resource - maxLength: 255 - type: string name: description: name of the existing resource maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - notTags: - description: |- - notTags is a list of tags to filter by. If specified, resources which - contain all of the given tags will be excluded from the result. - items: - maxLength: 80 - minLength: 1 - type: string - maxItems: 50 - type: array - x-kubernetes-list-type: set - notTagsAny: - description: |- - notTagsAny is a list of tags to filter by. If specified, resources - which contain any of the given tags will be excluded from the result. - items: - maxLength: 80 - minLength: 1 - type: string - maxItems: 50 - type: array - x-kubernetes-list-type: set - tags: - description: |- - tags is a list of tags to filter by. If specified, the resource must - have all of the tags specified to be included in the result. - items: - maxLength: 80 - minLength: 1 - type: string - maxItems: 50 - type: array - x-kubernetes-list-type: set - tagsAny: - description: |- - tagsAny is a list of tags to filter by. If specified, the resource - must have at least one of the tags specified to be included in the - result. - items: - maxLength: 80 - minLength: 1 - type: string - maxItems: 50 - type: array - x-kubernetes-list-type: set + type: + description: type of the existing resource + maxLength: 255 + minLength: 1 + type: string type: object id: description: |- @@ -5982,6 +7775,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -6004,153 +7798,50 @@ spec: default: managed description: |- managementPolicy defines how ORC will treat the object. Valid values are - `managed`: ORC will create, update, and delete the resource; `unmanaged`: - ORC will import an existing resource, and will not apply updates to it or - delete it. - enum: - - managed - - unmanaged - type: string - x-kubernetes-validations: - - message: managementPolicy is immutable - rule: self == oldSelf - resource: - description: |- - resource specifies the desired state of the resource. - - resource may not be specified if the management policy is `unmanaged`. - - resource must be specified if the management policy is `managed`. - properties: - availabilityZone: - description: availabilityZone is the availability zone in which - to create the server. - maxLength: 255 - type: string - x-kubernetes-validations: - - message: availabilityZone is immutable - rule: self == oldSelf - flavorRef: - description: flavorRef references the flavor to use for the server - instance. - maxLength: 253 - minLength: 1 - type: string - x-kubernetes-validations: - - message: flavorRef is immutable - rule: self == oldSelf - imageRef: - description: |- - imageRef references the image to use for the server instance. - NOTE: This is not required in case of boot from volume. - maxLength: 253 - minLength: 1 - type: string - x-kubernetes-validations: - - message: imageRef is immutable - rule: self == oldSelf - keypairRef: - description: |- - keypairRef is a reference to a KeyPair object. The server will be - created with this keypair for SSH access. - maxLength: 253 + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + description: + description: description indicates the description of service. + maxLength: 255 minLength: 1 type: string - x-kubernetes-validations: - - message: keypairRef is immutable - rule: self == oldSelf + enabled: + default: true + description: enabled indicates whether the service is enabled + or not. + type: boolean name: description: |- - name will be the name of the created resource. If not specified, the - name of the ORC object will be used. + name indicates the name of service. If not specified, the name of the ORC + resource will be used. maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - ports: - description: ports defines a list of ports which will be attached - to the server. - items: - maxProperties: 1 - minProperties: 1 - properties: - portRef: - description: |- - portRef is a reference to a Port object. Server creation will wait for - this port to be created and available. - maxLength: 253 - minLength: 1 - type: string - type: object - maxItems: 64 - type: array - x-kubernetes-list-type: atomic - serverGroupRef: - description: |- - serverGroupRef is a reference to a ServerGroup object. The server - will be created in the server group. - maxLength: 253 + type: + description: type indicates which resource the service is responsible + for. + maxLength: 255 minLength: 1 type: string - x-kubernetes-validations: - - message: serverGroupRef is immutable - rule: self == oldSelf - tags: - description: tags is a list of tags which will be applied to the - server. - items: - maxLength: 80 - minLength: 1 - type: string - maxItems: 50 - type: array - x-kubernetes-list-type: set - userData: - description: |- - userData specifies data which will be made available to the server at - boot time, either via the metadata service or a config drive. It is - typically read by a configuration service such as cloud-init or ignition. - maxProperties: 1 - minProperties: 1 - properties: - secretRef: - description: secretRef is a reference to a Secret containing - the user data for this server. - maxLength: 253 - minLength: 1 - type: string - type: object - x-kubernetes-validations: - - message: userData is immutable - rule: self == oldSelf - volumes: - description: volumes is a list of volumes attached to the server. - items: - minProperties: 1 - properties: - device: - description: |- - device is the name of the device, such as `/dev/vdb`. - Omit for auto-assignment - maxLength: 255 - type: string - volumeRef: - description: |- - volumeRef is a reference to a Volume object. Server creation will wait for - this volume to be created and available. - maxLength: 253 - minLength: 1 - type: string - required: - - volumeRef - type: object - maxItems: 64 - type: array - x-kubernetes-list-type: atomic required: - - flavorRef - - imageRef - - ports + - type type: object required: - cloudCredentialsRef @@ -6249,117 +7940,33 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack resource. properties: - availabilityZone: - description: availabilityZone is the availability zone where the - server is located. - maxLength: 1024 - type: string - hostID: - description: hostID is the host where the server is located in - the cloud. - maxLength: 1024 - type: string - imageID: - description: imageID indicates the OS image used to deploy the - server. - maxLength: 1024 + description: + description: description indicates the description of service. + maxLength: 255 type: string - interfaces: - description: interfaces contains the list of interfaces attached - to the server. - items: - properties: - fixedIPs: - description: fixedIPs is the list of fixed IP addresses - assigned to the interface. - items: - properties: - ipAddress: - description: ipAddress is the IP address assigned - to the port. - maxLength: 1024 - type: string - subnetID: - description: subnetID is the ID of the subnet from - which the IP address is allocated. - maxLength: 1024 - type: string - type: object - maxItems: 32 - type: array - x-kubernetes-list-type: atomic - macAddr: - description: macAddr is the MAC address of the interface. - maxLength: 1024 - type: string - netID: - description: netID is the ID of the network to which the - interface is attached. - maxLength: 1024 - type: string - portID: - description: portID is the ID of a port attached to the - server. - maxLength: 1024 - type: string - portState: - description: portState is the state of the port (e.g., ACTIVE, - DOWN). - maxLength: 1024 - type: string - type: object - maxItems: 64 - type: array - x-kubernetes-list-type: atomic + enabled: + description: enabled indicates whether the service is enabled + or not. + type: boolean name: - description: name is the human-readable name of the resource. - Might not be unique. - maxLength: 1024 + description: name indicates the name of service. + maxLength: 255 type: string - serverGroups: - description: |- - serverGroups is a slice of strings containing the UUIDs of the - server groups to which the server belongs. Currently this can - contain at most one entry. - items: - maxLength: 1024 - type: string - maxItems: 32 - type: array - x-kubernetes-list-type: atomic - status: - description: |- - status contains the current operational status of the server, - such as IN_PROGRESS or ACTIVE. - maxLength: 1024 + type: + description: type indicates which resource the service is responsible + for. + maxLength: 255 type: string - tags: - description: tags is the list of tags on the resource. - items: - maxLength: 1024 - type: string - maxItems: 50 - type: array - x-kubernetes-list-type: atomic - volumes: - description: volumes contains the volumes attached to the server. - items: - properties: - id: - description: id is the ID of a volume attached to the server. - maxLength: 1024 - type: string - type: object - maxItems: 64 - type: array - x-kubernetes-list-type: atomic type: object type: object + required: + - spec type: object served: true storage: true @@ -6370,17 +7977,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: services.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: subnets.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: Service - listKind: ServiceList - plural: services - singular: service + kind: Subnet + listKind: SubnetList + plural: subnets + singular: subnet scope: Namespaced versions: - additionalPrinterColumns: @@ -6399,7 +8006,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Service is the Schema for an ORC resource. + description: Subnet is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -6458,17 +8065,128 @@ spec: error state and will not continue to retry. minProperties: 1 properties: + cidr: + description: cidr of the existing resource + format: cidr + maxLength: 49 + minLength: 1 + type: string + description: + description: description of the existing resource + maxLength: 255 + minLength: 1 + type: string + gatewayIP: + description: gatewayIP is the IP address of the gateway of + the existing resource + maxLength: 45 + minLength: 1 + type: string + ipVersion: + description: ipVersion of the existing resource + enum: + - 4 + - 6 + format: int32 + type: integer + ipv6: + description: ipv6 options of the existing resource + minProperties: 1 + properties: + addressMode: + description: addressMode specifies mechanisms for assigning + IPv6 IP addresses. + enum: + - slaac + - dhcpv6-stateful + - dhcpv6-stateless + type: string + raMode: + description: |- + raMode specifies the IPv6 router advertisement mode. It specifies whether + the networking service should transmit ICMPv6 packets. + enum: + - slaac + - dhcpv6-stateful + - dhcpv6-stateless + type: string + type: object name: description: name of the existing resource maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - type: - description: type of the existing resource - maxLength: 255 + networkRef: + description: networkRef is a reference to the ORC Network + which this subnet is associated with. + maxLength: 253 + minLength: 1 + type: string + notTags: + description: |- + notTags is a list of tags to filter by. If specified, resources which + contain all of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + notTagsAny: + description: |- + notTagsAny is a list of tags to filter by. If specified, resources + which contain any of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + projectRef: + description: |- + projectRef is a reference to the ORC Project this resource is associated with. + Typically, only used by admin. + maxLength: 253 minLength: 1 type: string + tags: + description: |- + tags is a list of tags to filter by. If specified, the resource must + have all of the tags specified to be included in the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + tagsAny: + description: |- + tagsAny is a list of tags to filter by. If specified, the resource + must have at least one of the tags specified to be included in the + result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set type: object id: description: |- @@ -6476,6 +8194,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -6516,32 +8235,210 @@ spec: resource must be specified if the management policy is `managed`. properties: + allocationPools: + description: |- + allocationPools are IP Address pools that will be available for DHCP. IP + addresses must be in CIDR. + items: + properties: + end: + description: end is the last IP address in the allocation + pool. + maxLength: 45 + minLength: 1 + type: string + start: + description: start is the first IP address in the allocation + pool. + maxLength: 45 + minLength: 1 + type: string + required: + - end + - start + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + cidr: + description: cidr is the address CIDR of the subnet. It must match + the IP version specified in IPVersion. + format: cidr + maxLength: 49 + minLength: 1 + type: string + x-kubernetes-validations: + - message: cidr is immutable + rule: self == oldSelf description: - description: description indicates the description of service. + description: description is a human-readable description for the + resource. maxLength: 255 minLength: 1 type: string - enabled: - default: true - description: enabled indicates whether the service is enabled - or not. + dnsNameservers: + description: dnsNameservers are the nameservers to be set via + DHCP. + items: + maxLength: 45 + minLength: 1 + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: set + dnsPublishFixedIP: + description: |- + dnsPublishFixedIP will either enable or disable the publication of + fixed IPs to the DNS. Defaults to false. + type: boolean + x-kubernetes-validations: + - message: dnsPublishFixedIP is immutable + rule: self == oldSelf + enableDHCP: + description: enableDHCP will either enable to disable the DHCP + service. type: boolean + gateway: + description: |- + gateway specifies the default gateway of the subnet. If not specified, + neutron will add one automatically. To disable this behaviour, specify a + gateway with a type of None. + properties: + ip: + description: |- + ip is the IP address of the default gateway, which must be specified if + Type is `IP`. It must be a valid IP address, either IPv4 or IPv6, + matching the IPVersion in SubnetResourceSpec. + maxLength: 45 + minLength: 1 + type: string + type: + description: |- + type specifies how the default gateway will be created. `Automatic` + specifies that neutron will automatically add a default gateway. This is + also the default if no Gateway is specified. `None` specifies that the + subnet will not have a default gateway. `IP` specifies that the subnet + will use a specific address as the default gateway, which must be + specified in `IP`. + enum: + - None + - Automatic + - IP + type: string + required: + - type + type: object + hostRoutes: + description: hostRoutes are any static host routes to be set via + DHCP. + items: + properties: + destination: + description: destination for the additional route. + format: cidr + maxLength: 49 + minLength: 1 + type: string + nextHop: + description: nextHop for the additional route. + maxLength: 45 + minLength: 1 + type: string + required: + - destination + - nextHop + type: object + maxItems: 256 + type: array + x-kubernetes-list-type: atomic + ipVersion: + description: ipVersion is the IP version for the subnet. + enum: + - 4 + - 6 + format: int32 + type: integer + x-kubernetes-validations: + - message: ipVersion is immutable + rule: self == oldSelf + ipv6: + description: ipv6 contains IPv6-specific options. It may only + be set if IPVersion is 6. + minProperties: 1 + properties: + addressMode: + description: addressMode specifies mechanisms for assigning + IPv6 IP addresses. + enum: + - slaac + - dhcpv6-stateful + - dhcpv6-stateless + type: string + raMode: + description: |- + raMode specifies the IPv6 router advertisement mode. It specifies whether + the networking service should transmit ICMPv6 packets. + enum: + - slaac + - dhcpv6-stateful + - dhcpv6-stateless + type: string + type: object + x-kubernetes-validations: + - message: ipv6 is immutable + rule: self == oldSelf name: - description: |- - name indicates the name of service. If not specified, the name of the ORC - resource will be used. + description: name is a human-readable name of the subnet. If not + set, the object's name will be used. maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - type: - description: type indicates which resource the service is responsible - for. - maxLength: 255 + networkRef: + description: networkRef is a reference to the ORC Network which + this subnet is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: networkRef is immutable + rule: self == oldSelf + projectRef: + description: |- + projectRef is a reference to the ORC Project this resource is associated with. + Typically, only used by admin. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: projectRef is immutable + rule: self == oldSelf + routerRef: + description: routerRef specifies a router to attach the subnet + to + maxLength: 253 minLength: 1 type: string + x-kubernetes-validations: + - message: routerRef is immutable + rule: self == oldSelf + tags: + description: tags is a list of tags which will be applied to the + subnet. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set required: - - type + - cidr + - ipVersion + - networkRef type: object required: - cloudCredentialsRef @@ -6640,30 +8537,142 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack resource. properties: + allocationPools: + description: |- + allocationPools is a list of sub-ranges within CIDR available for dynamic + allocation to ports. + items: + properties: + end: + description: end is the last IP address in the allocation + pool. + maxLength: 1024 + type: string + start: + description: start is the first IP address in the allocation + pool. + maxLength: 1024 + type: string + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + cidr: + description: cidr representing IP range for this subnet, based + on IP version. + maxLength: 1024 + type: string + createdAt: + description: createdAt shows the date and time when the resource + was created. The date and time stamp format is ISO 8601 + format: date-time + type: string description: - description: description indicates the description of service. - maxLength: 255 + description: description is a human-readable description for the + resource. + maxLength: 1024 type: string - enabled: - description: enabled indicates whether the service is enabled - or not. + dnsNameservers: + description: dnsNameservers is a list of name servers used by + hosts in this subnet. + items: + maxLength: 1024 + type: string + maxItems: 16 + type: array + x-kubernetes-list-type: atomic + dnsPublishFixedIP: + description: dnsPublishFixedIP specifies whether the fixed IP + addresses are published to the DNS. + type: boolean + enableDHCP: + description: enableDHCP specifies whether DHCP is enabled for + this subnet or not. type: boolean + gatewayIP: + description: gatewayIP is the default gateway used by devices + in this subnet, if any. + maxLength: 1024 + type: string + hostRoutes: + description: |- + hostRoutes is a list of routes that should be used by devices with IPs + from this subnet (not including local subnet route). + items: + properties: + destination: + description: destination for the additional route. + maxLength: 1024 + type: string + nextHop: + description: nextHop for the additional route. + maxLength: 1024 + type: string + type: object + maxItems: 256 + type: array + x-kubernetes-list-type: atomic + ipVersion: + description: ipVersion specifies IP version, either `4' or `6'. + format: int32 + type: integer + ipv6AddressMode: + description: ipv6AddressMode specifies mechanisms for assigning + IPv6 IP addresses. + maxLength: 1024 + type: string + ipv6RAMode: + description: |- + ipv6RAMode is the IPv6 router advertisement mode. It specifies + whether the networking service should transmit ICMPv6 packets. + maxLength: 1024 + type: string name: - description: name indicates the name of service. - maxLength: 255 + description: name is the human-readable name of the subnet. Might + not be unique. + maxLength: 1024 type: string - type: - description: type indicates which resource the service is responsible - for. - maxLength: 255 + networkID: + description: networkID is the ID of the network to which the subnet + belongs. + maxLength: 1024 + type: string + projectID: + description: projectID is the project owner of the subnet. + maxLength: 1024 + type: string + revisionNumber: + description: revisionNumber optionally set via extensions/standard-attr-revisions + format: int64 + type: integer + subnetPoolID: + description: subnetPoolID is the id of the subnet pool associated + with the subnet. + maxLength: 1024 + type: string + tags: + description: tags optionally set via extensions/attributestags + items: + maxLength: 1024 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: atomic + updatedAt: + description: updatedAt shows the date and time when the resource + was updated. The date and time stamp format is ISO 8601 + format: date-time type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -6674,17 +8683,17 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 - name: subnets.openstack.k-orc.cloud + controller-gen.kubebuilder.io/version: v0.20.1 + name: trunks.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud names: categories: - openstack - kind: Subnet - listKind: SubnetList - plural: subnets - singular: subnet + kind: Trunk + listKind: TrunkList + plural: trunks + singular: trunk scope: Namespaced versions: - additionalPrinterColumns: @@ -6703,7 +8712,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: Subnet is the Schema for an ORC resource. + description: Trunk is the Schema for an ORC resource. properties: apiVersion: description: |- @@ -6744,82 +8753,39 @@ spec: minLength: 1 type: string required: - - cloudName - - secretName - type: object - import: - description: |- - import refers to an existing OpenStack resource which will be imported instead of - creating a new one. - maxProperties: 1 - minProperties: 1 - properties: - filter: - description: |- - filter contains a resource query which is expected to return a single - result. The controller will continue to retry if filter returns no - results. If filter returns multiple results the controller will set an - error state and will not continue to retry. - minProperties: 1 - properties: - cidr: - description: cidr of the existing resource - format: cidr - maxLength: 49 - minLength: 1 - type: string - description: - description: description of the existing resource - maxLength: 255 - minLength: 1 - type: string - gatewayIP: - description: gatewayIP is the IP address of the gateway of - the existing resource - maxLength: 45 - minLength: 1 - type: string - ipVersion: - description: ipVersion of the existing resource - enum: - - 4 - - 6 - format: int32 - type: integer - ipv6: - description: ipv6 options of the existing resource - minProperties: 1 - properties: - addressMode: - description: addressMode specifies mechanisms for assigning - IPv6 IP addresses. - enum: - - slaac - - dhcpv6-stateful - - dhcpv6-stateless - type: string - raMode: - description: |- - raMode specifies the IPv6 router advertisement mode. It specifies whether - the networking service should transmit ICMPv6 packets. - enum: - - slaac - - dhcpv6-stateful - - dhcpv6-stateless - type: string - type: object + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + adminStateUp: + description: adminStateUp is the administrative state of the + trunk. + type: boolean + description: + description: description of the existing resource + maxLength: 255 + minLength: 1 + type: string name: description: name of the existing resource maxLength: 255 minLength: 1 pattern: ^[^,]+$ type: string - networkRef: - description: networkRef is a reference to the ORC Network - which this subnet is associated with. - maxLength: 253 - minLength: 1 - type: string notTags: description: |- notTags is a list of tags to filter by. If specified, resources which @@ -6848,10 +8814,15 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: set + portRef: + description: portRef is a reference to the ORC Port which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string projectRef: - description: |- - projectRef is a reference to the ORC Project this resource is associated with. - Typically, only used by admin. + description: projectRef is a reference to the ORC Project + which this resource is associated with. maxLength: 253 minLength: 1 type: string @@ -6891,6 +8862,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -6908,234 +8880,510 @@ spec: - delete - detach type: string - type: object - managementPolicy: - default: managed - description: |- - managementPolicy defines how ORC will treat the object. Valid values are - `managed`: ORC will create, update, and delete the resource; `unmanaged`: - ORC will import an existing resource, and will not apply updates to it or - delete it. - enum: - - managed - - unmanaged - type: string - x-kubernetes-validations: - - message: managementPolicy is immutable - rule: self == oldSelf - resource: - description: |- - resource specifies the desired state of the resource. - - resource may not be specified if the management policy is `unmanaged`. - - resource must be specified if the management policy is `managed`. - properties: - allocationPools: - description: |- - allocationPools are IP Address pools that will be available for DHCP. IP - addresses must be in CIDR. + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + adminStateUp: + description: |- + adminStateUp is the administrative state of the trunk. If false (down), + the trunk does not forward packets. + type: boolean + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + portRef: + description: portRef is a reference to the ORC Port which this + resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: portRef is immutable + rule: self == oldSelf + projectRef: + description: projectRef is a reference to the ORC Project which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: projectRef is immutable + rule: self == oldSelf + subports: + description: subports is the list of ports to attach to the trunk. + items: + description: |- + TrunkSubportSpec represents a subport to attach to a trunk. + It maps to gophercloud's trunks.Subport. + properties: + portRef: + description: portRef is a reference to the ORC Port that + will be attached as a subport. + maxLength: 253 + minLength: 1 + type: string + segmentationID: + description: segmentationID is the segmentation ID for the + subport (e.g. VLAN ID). + format: int32 + maximum: 4094 + minimum: 1 + type: integer + segmentationType: + description: segmentationType is the segmentation type for + the subport (e.g. vlan). + enum: + - inherit + - vlan + maxLength: 32 + minLength: 1 + type: string + required: + - portRef + - segmentationID + - segmentationType + type: object + maxItems: 1024 + type: array + x-kubernetes-list-type: atomic + tags: + description: tags is a list of Neutron tags to apply to the trunk. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + maxLength: 255 + minLength: 1 + type: string + maxItems: 64 + type: array + x-kubernetes-list-type: set + required: + - portRef + type: object + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + adminStateUp: + description: adminStateUp is the administrative state of the trunk. + type: boolean + createdAt: + description: createdAt shows the date and time when the resource + was created. The date and time stamp format is ISO 8601 + format: date-time + type: string + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + name: + description: name is a Human-readable name for the resource. Might + not be unique. + maxLength: 1024 + type: string + portID: + description: portID is the ID of the Port to which the resource + is associated. + maxLength: 1024 + type: string + projectID: + description: projectID is the ID of the Project to which the resource + is associated. + maxLength: 1024 + type: string + revisionNumber: + description: revisionNumber optionally set via extensions/standard-attr-revisions + format: int64 + type: integer + status: + description: status indicates whether the trunk is currently operational. + maxLength: 1024 + type: string + subports: + description: subports is a list of ports associated with the trunk. items: + description: |- + TrunkSubportStatus represents an attached subport on a trunk. + It maps to gophercloud's trunks.Subport. properties: - end: - description: end is the last IP address in the allocation - pool. - maxLength: 45 - minLength: 1 + portID: + description: portID is the OpenStack ID of the Port attached + as a subport. + maxLength: 1024 type: string - start: - description: start is the first IP address in the allocation - pool. - maxLength: 45 - minLength: 1 + segmentationID: + description: segmentationID is the segmentation ID for the + subport (e.g. VLAN ID). + format: int32 + type: integer + segmentationType: + description: segmentationType is the segmentation type for + the subport (e.g. vlan). + maxLength: 1024 type: string - required: - - end - - start type: object - maxItems: 32 + maxItems: 1024 type: array x-kubernetes-list-type: atomic - cidr: - description: cidr is the address CIDR of the subnet. It must match - the IP version specified in IPVersion. - format: cidr - maxLength: 49 - minLength: 1 - type: string - x-kubernetes-validations: - - message: cidr is immutable - rule: self == oldSelf - description: - description: description is a human-readable description for the - resource. - maxLength: 255 - minLength: 1 - type: string - dnsNameservers: - description: dnsNameservers are the nameservers to be set via - DHCP. + tags: + description: tags is the list of tags on the resource. items: - maxLength: 45 - minLength: 1 + maxLength: 1024 type: string - maxItems: 16 + maxItems: 64 type: array - x-kubernetes-list-type: set - dnsPublishFixedIP: + x-kubernetes-list-type: atomic + tenantID: + description: tenantID is the project owner of the trunk (alias + of projectID in some deployments). + maxLength: 1024 + type: string + updatedAt: + description: updatedAt shows the date and time when the resource + was updated. The date and time stamp format is ISO 8601 + format: date-time + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: users.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: User + listKind: UserList + plural: users + singular: user + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: User is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: description: |- - dnsPublishFixedIP will either enable or disable the publication of - fixed IPs to the DNS. Defaults to false. - type: boolean - x-kubernetes-validations: - - message: dnsPublishFixedIP is immutable - rule: self == oldSelf - enableDHCP: - description: enableDHCP will either enable to disable the DHCP - service. - type: boolean - gateway: + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: description: |- - gateway specifies the default gateway of the subnet. If not specified, - neutron will add one automatically. To disable this behaviour, specify a - gateway with a type of None. - properties: - ip: - description: |- - ip is the IP address of the default gateway, which must be specified if - Type is `IP`. It must be a valid IP address, either IPv4 or IPv6, - matching the IPVersion in SubnetResourceSpec. - maxLength: 45 - minLength: 1 - type: string - type: - description: |- - type specifies how the default gateway will be created. `Automatic` - specifies that neutron will automatically add a default gateway. This is - also the default if no Gateway is specified. `None` specifies that the - subnet will not have a default gateway. `IP` specifies that the subnet - will use a specific address as the default gateway, which must be - specified in `IP`. - enum: - - None - - Automatic - - IP - type: string - required: - - type - type: object - hostRoutes: - description: hostRoutes are any static host routes to be set via - DHCP. - items: - properties: - destination: - description: destination for the additional route. - format: cidr - maxLength: 49 - minLength: 1 - type: string - nextHop: - description: nextHop for the additional route. - maxLength: 45 - minLength: 1 - type: string - required: - - destination - - nextHop - type: object - maxItems: 256 - type: array - x-kubernetes-list-type: atomic - ipVersion: - description: ipVersion is the IP version for the subnet. - enum: - - 4 - - 6 - format: int32 - type: integer - x-kubernetes-validations: - - message: ipVersion is immutable - rule: self == oldSelf - ipv6: - description: ipv6 contains IPv6-specific options. It may only - be set if IPVersion is 6. - minProperties: 1 - properties: - addressMode: - description: addressMode specifies mechanisms for assigning - IPv6 IP addresses. - enum: - - slaac - - dhcpv6-stateful - - dhcpv6-stateless + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. + maxLength: 253 + minLength: 1 type: string - raMode: - description: |- - raMode specifies the IPv6 router advertisement mode. It specifies whether - the networking service should transmit ICMPv6 packets. - enum: - - slaac - - dhcpv6-stateful - - dhcpv6-stateless + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ type: string type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + defaultProjectRef: + description: defaultProjectRef is a reference to the Default Project + which this resource is associated with. + maxLength: 253 + minLength: 1 + type: string x-kubernetes-validations: - - message: ipv6 is immutable + - message: defaultProjectRef is immutable rule: self == oldSelf - name: - description: name is a human-readable name of the subnet. If not - set, the object's name will be used. + description: + description: description is a human-readable description for the + resource. maxLength: 255 minLength: 1 - pattern: ^[^,]+$ type: string - networkRef: - description: networkRef is a reference to the ORC Network which - this subnet is associated with. + domainRef: + description: domainRef is a reference to the ORC Domain which + this resource is associated with. maxLength: 253 minLength: 1 type: string x-kubernetes-validations: - - message: networkRef is immutable + - message: domainRef is immutable rule: self == oldSelf - projectRef: + enabled: + description: enabled defines whether a user is enabled or disabled + type: boolean + name: description: |- - projectRef is a reference to the ORC Project this resource is associated with. - Typically, only used by admin. - maxLength: 253 + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 minLength: 1 + pattern: ^[^,]+$ type: string - x-kubernetes-validations: - - message: projectRef is immutable - rule: self == oldSelf - routerRef: - description: routerRef specifies a router to attach the subnet - to + passwordRef: + description: |- + passwordRef is a reference to a Secret containing the password + for this user. The Secret must contain a key named "password". + If not specified, the user is created without a password. maxLength: 253 minLength: 1 type: string - x-kubernetes-validations: - - message: routerRef is immutable - rule: self == oldSelf - tags: - description: tags is a list of tags which will be applied to the - subnet. - items: - description: |- - NeutronTag represents a tag on a Neutron resource. - It may not be empty and may not contain commas. - maxLength: 255 - minLength: 1 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: set - required: - - cidr - - ipVersion - - networkRef type: object + x-kubernetes-validations: + - message: passwordRef may not be removed once set + rule: '!has(oldSelf.passwordRef) || has(self.passwordRef)' required: - cloudCredentialsRef type: object @@ -7233,139 +9481,50 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack resource. properties: - allocationPools: + appliedPasswordRef: description: |- - allocationPools is a list of sub-ranges within CIDR available for dynamic - allocation to ports. - items: - properties: - end: - description: end is the last IP address in the allocation - pool. - maxLength: 1024 - type: string - start: - description: start is the first IP address in the allocation - pool. - maxLength: 1024 - type: string - type: object - maxItems: 32 - type: array - x-kubernetes-list-type: atomic - cidr: - description: cidr representing IP range for this subnet, based - on IP version. + appliedPasswordRef is the name of the Secret containing the + password that was last applied to the OpenStack resource. maxLength: 1024 type: string - createdAt: - description: createdAt shows the date and time when the resource - was created. The date and time stamp format is ISO 8601 - format: date-time + defaultProjectID: + description: defaultProjectID is the ID of the Default Project + to which the user is associated with. + maxLength: 1024 type: string description: description: description is a human-readable description for the resource. maxLength: 1024 type: string - dnsNameservers: - description: dnsNameservers is a list of name servers used by - hosts in this subnet. - items: - maxLength: 1024 - type: string - maxItems: 16 - type: array - x-kubernetes-list-type: atomic - dnsPublishFixedIP: - description: dnsPublishFixedIP specifies whether the fixed IP - addresses are published to the DNS. - type: boolean - enableDHCP: - description: enableDHCP specifies whether DHCP is enabled for - this subnet or not. - type: boolean - gatewayIP: - description: gatewayIP is the default gateway used by devices - in this subnet, if any. - maxLength: 1024 - type: string - hostRoutes: - description: |- - hostRoutes is a list of routes that should be used by devices with IPs - from this subnet (not including local subnet route). - items: - properties: - destination: - description: destination for the additional route. - maxLength: 1024 - type: string - nextHop: - description: nextHop for the additional route. - maxLength: 1024 - type: string - type: object - maxItems: 256 - type: array - x-kubernetes-list-type: atomic - ipVersion: - description: ipVersion specifies IP version, either `4' or `6'. - format: int32 - type: integer - ipv6AddressMode: - description: ipv6AddressMode specifies mechanisms for assigning - IPv6 IP addresses. - maxLength: 1024 - type: string - ipv6RAMode: - description: |- - ipv6RAMode is the IPv6 router advertisement mode. It specifies - whether the networking service should transmit ICMPv6 packets. + domainID: + description: domainID is the ID of the Domain to which the resource + is associated. maxLength: 1024 type: string + enabled: + description: enabled defines whether a user is enabled or disabled + type: boolean name: - description: name is the human-readable name of the subnet. Might + description: name is a Human-readable name for the resource. Might not be unique. maxLength: 1024 type: string - networkID: - description: networkID is the ID of the network to which the subnet - belongs. - maxLength: 1024 - type: string - projectID: - description: projectID is the project owner of the subnet. - maxLength: 1024 - type: string - revisionNumber: - description: revisionNumber optionally set via extensions/standard-attr-revisions - format: int64 - type: integer - subnetPoolID: - description: subnetPoolID is the id of the subnet pool associated - with the subnet. + passwordExpiresAt: + description: passwordExpiresAt is the timestamp at which the user's + password expires. maxLength: 1024 type: string - tags: - description: tags optionally set via extensions/attributestags - items: - maxLength: 1024 - type: string - maxItems: 64 - type: array - x-kubernetes-list-type: atomic - updatedAt: - description: updatedAt shows the date and time when the resource - was updated. The date and time stamp format is ISO 8601 - format: date-time - type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -7376,7 +9535,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: volumes.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -7492,6 +9651,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -7546,6 +9706,17 @@ spec: maxLength: 255 minLength: 1 type: string + imageRef: + description: |- + imageRef is a reference to an ORC Image. If specified, creates a + bootable volume from this image. The volume size must be >= the + image's min_disk requirement. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: imageRef is immutable + rule: self == oldSelf metadata: description: |- metadata key and value pairs to be associated with the volume. @@ -7696,6 +9867,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -7762,6 +9934,11 @@ spec: description: host is the identifier of the host holding the volume. maxLength: 1024 type: string + imageID: + description: imageID is the ID of the image this volume was created + from, if any. + maxLength: 1024 + type: string metadata: description: metadata key and value pairs to be associated with the volume. @@ -7829,6 +10006,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -7839,7 +10018,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.1 + controller-gen.kubebuilder.io/version: v0.20.1 name: volumetypes.openstack.k-orc.cloud spec: group: openstack.k-orc.cloud @@ -7949,6 +10128,7 @@ spec: that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist. format: uuid + maxLength: 36 type: string type: object managedOptions: @@ -8124,6 +10304,7 @@ spec: x-kubernetes-list-type: map id: description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 type: string resource: description: resource contains the observed state of the OpenStack @@ -8161,6 +10342,8 @@ spec: type: string type: object type: object + required: + - spec type: object served: true storage: true @@ -8285,7 +10468,10 @@ rules: - apiGroups: - openstack.k-orc.cloud resources: + - addressscopes + - applicationcredentials - domains + - endpoints - flavors - floatingips - groups @@ -8302,6 +10488,8 @@ rules: - servers - services - subnets + - trunks + - users - volumes - volumetypes verbs: @@ -8315,7 +10503,10 @@ rules: - apiGroups: - openstack.k-orc.cloud resources: + - addressscopes/status + - applicationcredentials/status - domains/status + - endpoints/status - flavors/status - floatingips/status - groups/status @@ -8332,6 +10523,8 @@ rules: - servers/status - services/status - subnets/status + - trunks/status + - users/status - volumes/status - volumetypes/status verbs: @@ -8459,7 +10652,7 @@ spec: - --health-probe-bind-address=:8081 command: - /manager - image: quay.io/orc/openstack-resource-controller:v2.4.0 + image: quay.io/orc/openstack-resource-controller:v2.5.0 livenessProbe: httpGet: path: /healthz diff --git a/enhancements/README.md b/enhancements/README.md new file mode 100644 index 000000000..a5013ceb2 --- /dev/null +++ b/enhancements/README.md @@ -0,0 +1,104 @@ +# ORC Enhancement Process + +This document describes the process for proposing significant changes to ORC. +The process is intentionally lightweight, inspired by the [Kubernetes +Enhancement Proposal (KEP)][kep] process but tailored to ORC's scope and +community size. + +[kep]: https://github.com/kubernetes/enhancements/tree/master/keps + +## When to Write an Enhancement + +Write an enhancement proposal when you want to: + +- Add a significant new feature or capability +- Make breaking changes to existing APIs +- Deprecate or remove functionality +- Make cross-cutting architectural changes +- Change behavior that users depend on + +You do **not** need an enhancement for: + +- Bug fixes +- Small improvements or refactoring +- Documentation updates +- Adding support for additional OpenStack resource fields +- Test improvements + +When in doubt, open a GitHub issue first to discuss whether an enhancement +proposal is needed. + +## Enhancement Lifecycle + +Enhancements move through the following statuses: + +| Status | Description | +|--------|-------------| +| `implementable` | The enhancement has been approved and is ready for implementation. | +| `implemented` | The enhancement has been fully implemented and merged. | +| `withdrawn` | The enhancement is no longer being pursued. | + +## How to Submit an Enhancement + +1. **Copy the template** from [TEMPLATE.md](TEMPLATE.md) to a new file named + after your feature: + ``` + enhancements/your-feature-name.md + ``` + + If your enhancement requires supporting files (images, diagrams), create a + directory instead: + ``` + enhancements/your-feature-name/ + ├── your-feature-name.md + └── diagram.png + ``` + +2. **Fill out the template** with your proposal details. + +3. **Open a pull request** with your enhancement proposal. Use a descriptive + title like: `Enhancement: Add support for feature X` + +4. **Iterate based on feedback**. Discussion happens on the PR. + +5. **Create a tracking issue** once the enhancement is merged. Label the issue + with `enhancement` and link it in your enhancement's metadata table. + +## Review Process + +- Any community member can propose an enhancement +- Maintainers review proposals and provide feedback on the PR +- Enhancements are approved using lazy consensus: if no maintainer has objected + after a reasonable review period (typically one week), the enhancement can be + merged +- The enhancement author is typically expected to drive implementation, though + others may volunteer + +## Directory Structure + +``` +enhancements/ +├── README.md # This document +├── TEMPLATE.md # Template for new enhancements +├── your-feature-name.md # Simple enhancement (single file) +└── complex-feature/ # Enhancement with supporting files + ├── complex-feature.md + └── architecture.png +``` + +## Tips for Writing Good Enhancements + +1. **Be concise but complete**. Include enough detail for reviewers to + understand the proposal without unnecessary verbosity. + +2. **Focus on the "why"**. Motivation is often more important than + implementation details. + +3. **Think about edge cases**. The Risks and Edge Cases section is where you + demonstrate you've thought through the implications. + +4. **Consider alternatives**. Showing that you've evaluated other approaches + strengthens your proposal. + +5. **Keep it updated**. As implementation progresses, update the Implementation + History section. diff --git a/enhancements/TEMPLATE.md b/enhancements/TEMPLATE.md new file mode 100644 index 000000000..205479cfa --- /dev/null +++ b/enhancements/TEMPLATE.md @@ -0,0 +1,102 @@ +# Enhancement: Your Feature Title + + + +| Field | Value | +|-------|-------| +| **Status** | implementable | +| **Author(s)** | @your-github-username | +| **Created** | YYYY-MM-DD | +| **Last Updated** | YYYY-MM-DD | +| **Tracking Issue** | TBD | + +## Summary + + + +## Motivation + + + +## Goals + + + +## Non-Goals + + + +## Proposal + + + +## Risks and Edge Cases + + + +## Alternatives Considered + + + +## Implementation History + + + +- YYYY-MM-DD: Enhancement proposed diff --git a/enhancements/drift-detection.md b/enhancements/drift-detection.md new file mode 100644 index 000000000..d63302a8c --- /dev/null +++ b/enhancements/drift-detection.md @@ -0,0 +1,280 @@ +# Enhancement: Drift Detection and Automatic Reconciliation + +| Field | Value | +|-------|-------| +| **Status** | implemented | +| **Author(s)** | @eshulman | +| **Created** | 2026-02-03 | +| **Last Updated** | 2026-07-05 | +| **Tracking Issue** | TBD | + +## Summary + +This enhancement introduces drift detection and automatic reconciliation for ORC managed resources. The feature enables ORC to periodically check OpenStack resources for changes made outside of ORC (via CLI, dashboard, or other tools) and automatically restore them to match the desired state defined in the Kubernetes specification. + +Additionally, managed resources that are deleted externally from OpenStack will be automatically recreated by ORC, ensuring the declared state is maintained. + +## Motivation + +In production environments, OpenStack resources may be modified outside of ORC through various means: + +- Direct OpenStack CLI/SDK operations +- OpenStack Horizon dashboard +- Other automation tools or controllers +- Manual emergency interventions +- Third-party integrations + +Without drift detection, these changes go unnoticed until they cause issues, leading to configuration drift between the declared Kubernetes state and the actual OpenStack state. This undermines the declarative model that ORC provides. + +Similar Kubernetes controllers for cloud resources have implemented drift detection: + +- **AWS Controllers for Kubernetes (ACK)**: Drift detection is **enabled by default** with a 10-hour resync period. Uses a detect-then-correct approach: periodically describes the AWS resource and only updates if drift is found. Configuration is set per-controller by authors, not configurable per-resource by users. No per-resource opt-out mechanism documented. ([ACK Drift Recovery docs](https://aws-controllers-k8s.github.io/community/docs/user-docs/drift-recovery/)) + +- **Azure Service Operator (ASO)**: Drift detection is **enabled by default** with a 1-hour resync period. Uses a PUT-on-every-reconcile approach rather than detect-then-correct. Provides **per-resource opt-out** via `reconcile-policy` annotation for adopted resources users don't want fully managed. **Global configuration** via `AZURE_SYNC_PERIOD` environment variable. Rate limiting via token-bucket algorithm and `MAX_CONCURRENT_RECONCILES` for parallelism control. ([ASO Controller Settings](https://azure.github.io/azure-service-operator/guide/aso-controller-settings-options/), [ASO Change Detection ADR](https://azure.github.io/azure-service-operator/design/adr-2022-11-change-detection/)) + +**Key design observations:** +- Both projects enable drift detection by default +- ASO provides more user-facing configuration options (global and per-resource) +- Neither project documents behavior for externally-deleted resources + +## Goals + +- **Ensure state consistency**: Managed resources in OpenStack should match the desired state declared in Kubernetes +- **Detect external modifications**: Identify when OpenStack resources are modified outside of ORC +- **Automatic correction**: Restore drifted resources to their desired state without manual intervention +- **Resource recreation**: Recreate managed resources that are deleted externally from OpenStack +- **Configurable frequency**: Allow operators to tune the resync interval based on their requirements +- **Hierarchical configuration**: Support configuration at ORC-wide and per-resource levels, at minimum +- **Minimal API impact**: Avoid excessive OpenStack API calls that could trigger rate limiting + +## Non-Goals + +- **Real-time drift detection**: Event-driven detection of changes (would require OpenStack webhooks or very short polling intervals) +- **Drift reporting without correction**: Alerting on drift without taking corrective action. This applies to both mutable fields (which are corrected, not just reported) and immutable fields (which are ignored, not reported). May be considered as a future enhancement. +- **Selective field reconciliation**: Allowing some fields to drift while correcting others +- **Conflict resolution with merge semantics**: Merging external changes with desired state +- **Drift correction for unmanaged resources**: Unmanaged resources are not modified by ORC; however, periodic resync will refresh their status to reflect the current OpenStack state + +## Proposal + +### Periodic Resync Mechanism + +The drift detection mechanism works by periodically triggering reconciliation of resources. Unlike event-driven reconciles (triggered by Kubernetes spec/status changes), drift detection uses a time-based trigger to catch changes made directly in OpenStack. For managed resources, this includes drift correction; for unmanaged resources, this refreshes the status only. + +1. **Trigger**: After a resource reaches a stable state (Progressing=False), ORC schedules a resync after `resyncPeriod` duration +2. **Fetch**: On resync, ORC fetches the current state of the OpenStack resource +3. **Compare**: The current state is compared against the desired state in the Kubernetes spec +4. **Update**: If drift is detected, ORC updates the OpenStack resource to match the desired state +5. **Reschedule**: After successful reconciliation, the next resync is scheduled + +#### Implementation Details + +At the end of a successful reconciliation (when no other reschedule is pending), the controller schedules the next resync: + +```go +// If periodic resync is enabled and we're not already rescheduling for +// another reason, schedule the next resync to detect drift. +if resyncPeriod > 0 { + needsReschedule, _ := reconcileStatus.NeedsReschedule() + if !needsReschedule { + reconcileStatus = reconcileStatus.WithRequeue(resyncPeriod) + } +} +``` + +This ensures the controller automatically triggers reconciliation after the configured period. + +Additionally, `shouldReconcile` must be updated to allow periodic resync. Currently it returns `false` when `Progressing=False` and generation is current, which would discard resync requests. The updated logic checks the last sync timestamp: + +```go +func shouldReconcile(obj orcv1alpha1.ObjectWithConditions, resyncPeriod time.Duration) bool { + // ... existing checks ... + + // At this point, Progressing is False and generation is up to date. + // For periodic resync, check if enough time has passed since the last sync. + if resyncPeriod > 0 { + if lastSync := obj.GetLastSyncTime(); lastSync != nil { + return time.Since(lastSync.Time) >= resyncPeriod + } + return true // First sync after feature enablement + } + return false +} +``` + +**Note**: Using `Progressing.LastTransitionTime` is not suitable because it only updates when the condition value changes, not on every reconcile. A dedicated `LastSyncTime` status field is required (see Status Changes below). + +**Resources in terminal error are not resynced**: When a resource is in a terminal error state (e.g., invalid configuration, unrecoverable OpenStack error), periodic resync is not scheduled. Terminal errors indicate issues that cannot be resolved through automatic retry and require manual intervention to fix the underlying problem. This prevents wasted reconciliation cycles on resources that are known to be in an unrecoverable state. + +### API Changes + +A `resyncPeriod` field is added at the spec level, making it available to both managed and unmanaged resources: + +```yaml +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: critical-network +spec: + cloudCredentialsRef: + secretName: openstack-clouds + cloudName: openstack + managementPolicy: managed + resyncPeriod: 1h # Periodic resync every hour + resource: + description: Critical application network +``` + +**Default**: Disabled (`0`). Set a positive duration like `10h` to enable. + +### Status Changes + +A new `lastSyncTime` field is added to the status of all ORC resources: + +```yaml +status: + lastSyncTime: "2026-02-03T10:30:00Z" # Last successful reconciliation with OpenStack + id: "abc123" + # ... other status fields +``` + +This field is updated at the end of every successful reconciliation that fetches the resource from OpenStack. It is required because: + +1. **Controller restarts**: Without persisted state, the controller would lose track of when resources were last synced, potentially causing a thundering herd of reconciliations on restart. +2. **Accurate timing**: The `Progressing.LastTransitionTime` only updates when the condition value changes, not on every reconcile, making it unsuitable for tracking sync intervals. + +The `shouldReconcile` function uses this field to determine if enough time has passed since the last sync to trigger a periodic resync. + +### Behavior by Management Policy + +The periodic resync behavior differs based on `managementPolicy`: + +| Policy | On Resync | +|--------|-----------| +| `managed` | Fetch from OpenStack → correct drift → update status | +| `unmanaged` | Fetch from OpenStack → update status only (no writes to OpenStack) | + +This allows unmanaged/imported resources to keep their `status.resource` in sync with the actual OpenStack state without ORC modifying the resource. + +### Configuration Hierarchy + +Drift detection supports a two-level configuration hierarchy: + +| Level | Scope | Configuration Location | Precedence | +|-------|-------|----------------------|------------| +| ORC-wide | All resources across all types | CLI flag | Lowest | +| Per-resource | Individual resource instance | `spec.resyncPeriod` on the CR | Highest | + +**Resolution order**: Per-resource → ORC-wide → Built-in default (disabled) + +#### ORC-wide Configuration Options + +A CLI flag sets the global default: + +``` +--default-resync-period=10h +``` + +For per-resource-type configuration, platform teams can use [kro (Kube Resource Orchestrator)](https://kro.run/) to wrap ORC resources with organizational defaults without changes to ORC itself. + +### Resource Recreation on External Deletion + +When a resource with `managementPolicy=managed` is deleted from OpenStack but the ORC object still exists: + +1. On the next reconciliation, ORC attempts to fetch the resource by the ID stored in `status.id` +2. If not found and the resource was originally created by ORC (not imported), ORC recreates it +3. The new resource ID is stored in `status.id` + +#### Implementation Changes + +Currently, `GetOrCreateOSResource` returns a terminal error when fetching a resource by `status.id` results in a 404. To support resource recreation, this logic must be updated to: + +1. Check if `managementPolicy == managed` and the resource was not imported (no `importID` or `importFilter`) +2. If both conditions are met, return a typed `ExternallyDeleted` signal via `ReconcileStatus` so the caller can clear `status.id` and trigger recreation on the next reconcile +3. If the resource was imported or is unmanaged, retain the existing terminal error behavior +4. If `GetOSResourceByID` returns a nil resource with no error, return an explicit error rather than silently misinterpreting the invalid actuator response as external deletion + +This ensures that managed resources created by ORC are automatically recreated, while imported or unmanaged resources correctly fail with a terminal error when deleted externally. The typed signal keeps the external-deletion path distinct from invalid actuator responses. + +**Behavior when drift detection is disabled** (`resyncPeriod: 0`): Periodic resyncs do not occur, so discovery of external deletion depends on other triggers (spec change, controller restart). When discovered, ORC will still recreate managed resources (not a terminal error). The difference is timing of discovery, not the recreation behavior itself. + +For **imported resources** that are deleted externally, this is always a terminal error regardless of drift detection settings, because the resource was not created by ORC and recreating it would not restore the original resource. + +**Note on dependent resources**: OpenStack enforces referential integrity for most resources (e.g., Networks cannot be deleted while Subnets exist). If resources are deleted through means that bypass these checks (direct database manipulation, OpenStack bugs), drift detection preserves ORC's existing reconciliation behavior: + +- **Parent resource (e.g., Network)**: On next reconciliation, `GetOSResourceByID` returns 404 → terminal error ("resource has been deleted from OpenStack"). +- **Dependent resource update path (e.g., Subnet update)**: The controller doesn't check if its parent dependency is in terminal error. It fetches the resource by `status.id`, and if successful, proceeds with the update. The result depends on what OpenStack returns for that specific operation and would preserve the existing error handling behavior. +- **Dependent resource create/recreate path**: The controller checks `IsAvailable(parent)` before proceeding. If the parent is in terminal error, the dependent waits on the dependency (not terminal, just waiting). + +These behaviors exist regardless of drift detection—drift detection only changes scheduling, not reconciliation logic. Resolving such inconsistencies requires manual intervention. + +### Field Coverage + +Drift detection covers all **mutable fields** that ORC actuators implement update operations for. Before this feature is considered stable, all actuator implementations must be audited to ensure they cover all mutable fields. + +## Risks and Edge Cases + +### Split-Brain Scenarios + +**Risk**: Multiple controllers or systems may be managing the same OpenStack resources, leading to conflicts where changes are repeatedly overwritten. + +**Mitigation**: +- Document that ORC should be the sole manager of resources it creates +- Report conflicts in resource conditions for observability + +### API Rate Limiting + +**Risk**: Frequent resync across many resources could trigger OpenStack API rate limiting. + +**Mitigation**: +- Disabled by default; when enabled, recommend conservative intervals (e.g., 10 hours) +- Add random jitter to resync times to avoid thundering herd: since reconciliation already uses "requeue after X duration", jitter simply adds a random offset (e.g., [0%, +20%]) to the resync period, spreading resyncs over time rather than having them fire simultaneously +- Allow operators to disable or lengthen resync for stable resources + +### Controller Resource Consumption + +**Risk**: Frequent reconciliation increases CPU and memory usage on the ORC controller. + +**Mitigation**: +- Disabled by default; when enabled, conservative intervals limit reconciliation frequency + +### Conflicts with External Systems + +**Risk**: If resources are intentionally managed by external systems (e.g., autoscalers, other controllers), drift correction can cause unexpected behavior. + +**Mitigation**: +- Allow `resyncPeriod: 0` to disable drift detection +- Use `managementPolicy: unmanaged` for externally managed resources +- Document the implications clearly in the user guide + +### Upgrade/Downgrade Considerations + +**Risk**: Users upgrading to a version with drift detection may experience unexpected reconciliations. + +**Mitigation**: Drift detection is disabled by default (opt-in), so users upgrading will not experience any behavior change unless they explicitly enable it. Document the new feature in release notes. + +## Alternatives Considered + +### Event-Driven Drift Detection + +Use OpenStack notifications (Oslo messaging) to detect changes in real-time. + +**Rejected because**: Requires OpenStack notification infrastructure, complex to implement, not all deployments have notifications enabled. + +### Drift Detection Without Correction + +Detect and report drift without automatically correcting it. + +**Out of scope for this enhancement**: While drift notification has value for observability, it is better addressed as a separate alerting effort. This enhancement focuses on drift correction; reporting-only mode could be added as a future management policy option. + +### Watch-Based Detection + +Implement a watcher that periodically lists all resources from OpenStack and compares. + +**Rejected because**: List operations can be expensive, harder to implement with proper filtering, and per-resource reconciliation integrates naturally with controller-runtime. + +## Implementation History + +- 2026-02-03: Enhancement proposed +- 2026-07-05: Addition of explicit `ExternallyDeleted` reconcile status +- 2026-07-05: Initial implementation diff --git a/examples/bases/boot-from-volume/kustomization.yaml b/examples/bases/boot-from-volume/kustomization.yaml new file mode 100644 index 000000000..ce2cb1adc --- /dev/null +++ b/examples/bases/boot-from-volume/kustomization.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- volume.yaml +- server.yaml diff --git a/examples/bases/boot-from-volume/server.yaml b/examples/bases/boot-from-volume/server.yaml new file mode 100644 index 000000000..129203407 --- /dev/null +++ b/examples/bases/boot-from-volume/server.yaml @@ -0,0 +1,18 @@ +--- +# Server that boots from a volume instead of an image +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Server +metadata: + name: server +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: cloud-config + managementPolicy: managed + resource: + # No imageRef - booting from volume + bootVolume: + volumeRef: boot-volume + flavorRef: flavor + ports: + - portRef: port diff --git a/examples/bases/boot-from-volume/volume.yaml b/examples/bases/boot-from-volume/volume.yaml new file mode 100644 index 000000000..007353870 --- /dev/null +++ b/examples/bases/boot-from-volume/volume.yaml @@ -0,0 +1,14 @@ +--- +# Bootable volume created from the cirros image +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Volume +metadata: + name: boot-volume +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: cloud-config + managementPolicy: managed + resource: + size: 1 + imageRef: cirros diff --git a/examples/components/kustomizeconfig/kustomizeconfig.yaml b/examples/components/kustomizeconfig/kustomizeconfig.yaml index 90866d4e5..c8439d33b 100644 --- a/examples/components/kustomizeconfig/kustomizeconfig.yaml +++ b/examples/components/kustomizeconfig/kustomizeconfig.yaml @@ -25,6 +25,8 @@ nameReference: kind: Subnet - path: spec/cloudCredentialsRef/secretName kind: KeyPair + - path: spec/cloudCredentialsRef/secretName + kind: Trunk - kind: Network fieldSpecs: @@ -77,6 +79,12 @@ nameReference: kind: FloatingIP - path: spec/resource/ports[]/portRef kind: Server + - path: spec/resource/portRef + kind: Trunk + - path: spec/resource/subports[]/portRef + kind: Trunk + - path: spec/import/filter/portRef + kind: Trunk - kind: Project fieldSpecs: @@ -90,3 +98,7 @@ nameReference: kind: Port - path: spec/resource/projectRef kind: SecurityGroup + - path: spec/resource/projectRef + kind: Trunk + - path: spec/import/filter/projectRef + kind: Trunk diff --git a/go.mod b/go.mod index 0562d961f..e5a843da1 100644 --- a/go.mod +++ b/go.mod @@ -1,31 +1,32 @@ module github.com/k-orc/openstack-resource-controller/v2 -go 1.24.0 +go 1.25.0 require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/go-logr/logr v1.4.3 - github.com/gophercloud/gophercloud/v2 v2.9.0 + github.com/google/go-cmp v0.7.0 + github.com/gophercloud/gophercloud/v2 v2.13.0 github.com/gophercloud/utils/v2 v2.0.0-20241220104409-2e0af06694a1 - github.com/onsi/ginkgo/v2 v2.27.3 - github.com/onsi/gomega v1.38.3 + github.com/onsi/ginkgo/v2 v2.32.0 + github.com/onsi/gomega v1.42.1 github.com/ulikunitz/xz v0.5.15 go.uber.org/mock v0.6.0 - golang.org/x/text v0.32.0 - k8s.io/api v0.34.3 - k8s.io/apimachinery v0.34.3 - k8s.io/client-go v0.34.3 - k8s.io/code-generator v0.34.3 + golang.org/x/text v0.40.0 + k8s.io/api v0.34.9 + k8s.io/apimachinery v0.34.10 + k8s.io/client-go v0.34.9 + k8s.io/code-generator v0.34.9 k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 - sigs.k8s.io/controller-runtime v0.22.4 - sigs.k8s.io/structured-merge-diff/v6 v6.3.1 + sigs.k8s.io/controller-runtime v0.22.5 + sigs.k8s.io/structured-merge-diff/v6 v6.4.2 sigs.k8s.io/yaml v1.6.0 ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.1 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -49,8 +50,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.0 // indirect github.com/google/gnostic-models v0.7.0 // indirect - github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -70,40 +70,40 @@ require ( github.com/spf13/pflag v1.0.6 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect - go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/sdk v1.34.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.27.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect + golang.org/x/mod v0.37.0 // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/term v0.44.0 // indirect golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.47.0 // indirect golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/grpc v1.72.1 // indirect - google.golang.org/protobuf v1.36.7 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/grpc v1.79.3 // indirect + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.34.1 // indirect - k8s.io/apiserver v0.34.1 // indirect - k8s.io/component-base v0.34.1 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/apiserver v0.34.3 // indirect + k8s.io/component-base v0.34.3 // indirect k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect diff --git a/go.sum b/go.sum index 0d31f1ca9..d8e12d746 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= @@ -72,12 +72,12 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg= +github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gophercloud/gophercloud/v2 v2.9.0 h1:Y9OMrwKF9EDERcHFSOTpf/6XGoAI0yOxmsLmQki4LPM= -github.com/gophercloud/gophercloud/v2 v2.9.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk= +github.com/gophercloud/gophercloud/v2 v2.13.0 h1:yEyJG+kABd8x2ttTqLsomihU6Kg2YheJSZhvP/QSx+8= +github.com/gophercloud/gophercloud/v2 v2.13.0/go.mod h1:KZRLVs6gcoy/pEFdkZqFjdYqnS0emMHv66UqdM5lMjU= github.com/gophercloud/utils/v2 v2.0.0-20241220104409-2e0af06694a1 h1:LS70kbNdqoalMwLXEzP9Xb/cYv9UCzWioXaOynxrytc= github.com/gophercloud/utils/v2 v2.0.0-20241220104409-2e0af06694a1/go.mod h1:qDhuzCRKi90/Yyl/yEqkg8+qABEvK44LhP0D3GWKGtY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= @@ -117,10 +117,10 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8= -github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= -github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM= -github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= +github.com/onsi/ginkgo/v2 v2.32.0 h1:Hw7s2pVrQo/8Yz5N77qdnpHaoc+c6cC9WIV1Jce+J6E= +github.com/onsi/ginkgo/v2 v2.32.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= +github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -134,8 +134,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= @@ -152,8 +152,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -168,24 +168,24 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -207,40 +207,40 @@ golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/ golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= -golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY= golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -251,14 +251,16 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= -google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= -google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -269,20 +271,20 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= -k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= -k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= -k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= -k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= -k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= -k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= -k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= -k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= -k8s.io/code-generator v0.34.3 h1:6ipJKsJZZ9q21BO8I2jEj4OLN3y8/1n4aihKN0xKmQk= -k8s.io/code-generator v0.34.3/go.mod h1:oW73UPYpGLsbRN8Ozkhd6ZzkF8hzFCiYmvEuWZDroI4= -k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= -k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0= +k8s.io/api v0.34.9 h1:aVsK5NQL7146suJriGuvpi9giNpwIRSHJ8v5HWakwBo= +k8s.io/api v0.34.9/go.mod h1:8oYqD5tLKgvBSnkuDbHZTNrk7NTHybkfYjJ6lNjThjQ= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.10 h1:2TkKKtyUGjkdf1fTNEoANuv46QXFIi6UfMfrMxJ9Glg= +k8s.io/apimachinery v0.34.10/go.mod h1:gCxm98KdKjmJKLtGA2OQOIGmb3tY/csRmlQSymG3tLw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.9 h1:HlhSEGPyCFH5rQADW6NPKEziGns6ekgUCPK0OsOGU90= +k8s.io/client-go v0.34.9/go.mod h1:bI3Sqqmwls2JKFZOQN9h8oLaeibvIA5pqqJAaSJWnrk= +k8s.io/code-generator v0.34.9 h1:jXBgPd5FbFoN1J2uA/qISW3uLHRl8wJ9Gx6L4PiJIPk= +k8s.io/code-generator v0.34.9/go.mod h1:/doiEA33AIV4kFt4NTMCzV8N5Ued8kq1fZMWUUib990= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f h1:SLb+kxmzfA87x4E4brQzB33VBbT2+x7Zq9ROIHmGn9Q= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= @@ -293,13 +295,13 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= -sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= +sigs.k8s.io/controller-runtime v0.22.5 h1:v3nfSUMowX/2WMp27J9slwGFyAt7IV0YwBxAkrUr0GE= +sigs.k8s.io/controller-runtime v0.22.5/go.mod h1:pc5SoYWnWI6I+cBHYYdZ7B6YHZVY5xNfll88JB+vniI= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= -sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q= +sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index 329a83718..2bdfd71ce 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/hack/collectlogs b/hack/collectlogs index 2abb930dc..e41e524ad 100755 --- a/hack/collectlogs +++ b/hack/collectlogs @@ -27,7 +27,14 @@ done cp ./devstack/local.conf "$DEVSTACK_LOG_DIR" kubectl describe pods -n orc-system > "$LOG_DIR/orc-pod.txt" -kubectl logs -n orc-system -l control-plane=controller-manager --tail=-1 > "$LOG_DIR/orc-pod.log" + +ORC_POD=$(kubectl get pods -n orc-system -l control-plane=controller-manager -o jsonpath='{.items[0].metadata.name}') +kubectl logs -n orc-system "$ORC_POD" --tail=-1 > "$LOG_DIR/orc-pod.log" 2>&1 + +if [ ! -s "$LOG_DIR/orc-pod.log" ]; then + echo "WARNING: orc-pod.log is empty, trying --previous" >&2 + kubectl logs -n orc-system "$ORC_POD" --previous > "$LOG_DIR/orc-pod-previous.log" 2>&1 || true +fi kubectl get -n orc-system all -o yaml > "$LOG_DIR/orc-resources.yaml" diff --git a/internal/controllers/addressscope/actuator.go b/internal/controllers/addressscope/actuator.go new file mode 100644 index 000000000..6c75a4829 --- /dev/null +++ b/internal/controllers/addressscope/actuator.go @@ -0,0 +1,280 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addressscope + +import ( + "context" + "iter" + + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/addressscopes" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// OpenStack resource types +type ( + osResourceT = addressscopes.AddressScope + + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + resourceReconciler = interfaces.ResourceReconciler[orcObjectPT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) + +type addressscopeActuator struct { + osClient osclients.AddressScopeClient + k8sClient client.Client +} + +var _ createResourceActuator = addressscopeActuator{} +var _ deleteResourceActuator = addressscopeActuator{} + +func (addressscopeActuator) GetResourceID(osResource *osResourceT) string { + return osResource.ID +} + +func (actuator addressscopeActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) { + resource, err := actuator.osClient.GetAddressScope(ctx, id) + if err != nil { + return nil, progress.WrapError(err) + } + return resource, nil +} + +func (actuator addressscopeActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + // Resolve the project ID from ProjectRef if set. + var projectID string + if resourceSpec.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + + listOpts := addressscopes.ListOpts{ + Name: getResourceName(orcObject), + IPVersion: int(resourceSpec.IPVersion), + ProjectID: projectID, + } + + return actuator.osClient.ListAddressScopes(ctx, listOpts), true +} + +func (actuator addressscopeActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, + filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + listOpts := addressscopes.ListOpts{ + Name: string(ptr.Deref(filter.Name, "")), + ProjectID: ptr.Deref(project.Status.ID, ""), + IPVersion: int(filter.IPVersion), + Shared: filter.Shared, + } + + return actuator.osClient.ListAddressScopes(ctx, listOpts), reconcileStatus +} + +func (actuator addressscopeActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + var reconcileStatus progress.ReconcileStatus + + var projectID string + if resource.ProjectRef != nil { + project, projectDepRS := projectDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) + if project != nil { + projectID = ptr.Deref(project.Status.ID, "") + } + } + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + createOpts := addressscopes.CreateOpts{ + Name: getResourceName(obj), + ProjectID: projectID, + IPVersion: int(resource.IPVersion), + } + + if resource.Shared != nil { + createOpts.Shared = *resource.Shared + } + + osResource, err := actuator.osClient.CreateAddressScope(ctx, createOpts) + if err != nil { + // We should require the spec to be updated before retrying a create which returned a conflict + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + return osResource, nil +} + +func (actuator addressscopeActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + return progress.WrapError(actuator.osClient.DeleteAddressScope(ctx, resource.ID)) +} + +func (actuator addressscopeActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + // Should have been caught by API validation + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + + updateOpts := addressscopes.UpdateOpts{} + + handleNameUpdate(&updateOpts, obj, osResource) + handleSharedUpdate(&updateOpts, resource, osResource) + + needsUpdate, err := needsUpdate(updateOpts) + if err != nil { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err)) + } + if !needsUpdate { + log.V(logging.Debug).Info("No changes") + return nil + } + + _, err = actuator.osClient.UpdateAddressScope(ctx, osResource.ID, updateOpts) + + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) + } + + return progress.NeedsRefresh() +} + +func needsUpdate(updateOpts addressscopes.UpdateOpts) (bool, error) { + updateOptsMap, err := updateOpts.ToAddressScopeUpdateMap() + if err != nil { + return false, err + } + + updateMap, ok := updateOptsMap["address_scope"].(map[string]any) + if !ok { + updateMap = make(map[string]any) + } + + return len(updateMap) > 0, nil +} + +func handleNameUpdate(updateOpts *addressscopes.UpdateOpts, obj orcObjectPT, osResource *osResourceT) { + name := getResourceName(obj) + if osResource.Name != name { + updateOpts.Name = &name + } +} + +func handleSharedUpdate(updateOpts *addressscopes.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + shared := ptr.Deref(resource.Shared, false) + if shared != osResource.Shared { + updateOpts.Shared = &shared + } +} + +func (actuator addressscopeActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.updateResource, + }, nil +} + +type addressscopeHelperFactory struct{} + +var _ helperFactory = addressscopeHelperFactory{} + +func newActuator(ctx context.Context, orcObject *orcv1alpha1.AddressScope, controller interfaces.ResourceController) (addressscopeActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, controller.GetK8sClient(), orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return addressscopeActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject) + if err != nil { + return addressscopeActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewAddressScopeClient() + if err != nil { + return addressscopeActuator{}, progress.WrapError(err) + } + + return addressscopeActuator{ + osClient: osClient, + k8sClient: controller.GetK8sClient(), + }, nil +} + +func (addressscopeHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { + return addressscopeAdapter{obj} +} + +func (addressscopeHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} + +func (addressscopeHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} diff --git a/internal/controllers/addressscope/actuator_test.go b/internal/controllers/addressscope/actuator_test.go new file mode 100644 index 000000000..151595fb4 --- /dev/null +++ b/internal/controllers/addressscope/actuator_test.go @@ -0,0 +1,117 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addressscope + +import ( + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/addressscopes" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "k8s.io/utils/ptr" +) + +func TestNeedsUpdate(t *testing.T) { + testCases := []struct { + name string + updateOpts addressscopes.UpdateOpts + expectChange bool + }{ + { + name: "Empty base opts", + updateOpts: addressscopes.UpdateOpts{}, + expectChange: false, + }, + { + name: "Updated opts", + updateOpts: addressscopes.UpdateOpts{Name: ptr.To("updated")}, + expectChange: true, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + got, _ := needsUpdate(tt.updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestHandleNameUpdate(t *testing.T) { + ptrToName := ptr.To[orcv1alpha1.OpenStackName] + testCases := []struct { + name string + newValue *orcv1alpha1.OpenStackName + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToName("name"), existingValue: "name", expectChange: false}, + {name: "Different", newValue: ptrToName("new-name"), existingValue: "name", expectChange: true}, + {name: "No value provided, existing is identical to object name", newValue: nil, existingValue: "object-name", expectChange: false}, + {name: "No value provided, existing is different from object name", newValue: nil, existingValue: "different-from-object-name", expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.AddressScope{} + resource.Name = "object-name" + resource.Spec = orcv1alpha1.AddressScopeSpec{ + Resource: &orcv1alpha1.AddressScopeResourceSpec{Name: tt.newValue}, + } + osResource := &osResourceT{Name: tt.existingValue} + + updateOpts := addressscopes.UpdateOpts{} + handleNameUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleSharedUpdate(t *testing.T) { + testCases := []struct { + name string + newValue *bool + existingValue bool + expectChange bool + }{ + {name: "Identical true", newValue: ptr.To(true), existingValue: true, expectChange: false}, + {name: "Identical false", newValue: ptr.To(false), existingValue: false, expectChange: false}, + {name: "Change from false to true", newValue: ptr.To(true), existingValue: false, expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.AddressScopeResourceSpec{Shared: tt.newValue} + osResource := &osResourceT{Shared: tt.existingValue} + + updateOpts := addressscopes.UpdateOpts{} + handleSharedUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} diff --git a/internal/controllers/addressscope/controller.go b/internal/controllers/addressscope/controller.go new file mode 100644 index 000000000..718aa0f8b --- /dev/null +++ b/internal/controllers/addressscope/controller.go @@ -0,0 +1,120 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addressscope + +import ( + "context" + "errors" + "time" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "addressscope" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=addressscopes,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=addressscopes/status,verbs=get;update;patch + +type addressscopeReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return &addressscopeReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (addressscopeReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *addressscopeReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var projectDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.AddressScopeList, *orcv1alpha1.Project]( + "spec.resource.projectRef", + func(addressscope *orcv1alpha1.AddressScope) []string { + resource := addressscope.Spec.Resource + if resource == nil || resource.ProjectRef == nil { + return nil + } + return []string{string(*resource.ProjectRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var projectImportDependency = dependency.NewDependency[*orcv1alpha1.AddressScopeList, *orcv1alpha1.Project]( + "spec.import.filter.projectRef", + func(addressscope *orcv1alpha1.AddressScope) []string { + resource := addressscope.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.ProjectRef == nil { + return nil + } + return []string{string(*resource.Filter.ProjectRef)} + }, +) + +// SetupWithManager sets up the controller with the Manager. +func (c *addressscopeReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + projectWatchEventHandler, err := projectDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + projectImportWatchEventHandler, err := projectImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + Watches(&orcv1alpha1.Project{}, projectWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Project{}, projectImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ). + For(&orcv1alpha1.AddressScope{}) + + if err := errors.Join( + projectDependency.AddToManager(ctx, mgr), + projectImportDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, addressscopeHelperFactory{}, addressscopeStatusWriter{}, c.defaultResyncPeriod) + return builder.Complete(&r) +} diff --git a/internal/controllers/addressscope/status.go b/internal/controllers/addressscope/status.go new file mode 100644 index 000000000..5065adfad --- /dev/null +++ b/internal/controllers/addressscope/status.go @@ -0,0 +1,59 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addressscope + +import ( + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type addressscopeStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.AddressScopeApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.AddressScopeStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.AddressScope, *osResourceT, *objectApplyT, *statusApplyT] = addressscopeStatusWriter{} + +func (addressscopeStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.AddressScope(name, namespace) +} + +func (addressscopeStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.AddressScope, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource == nil { + if orcObject.Status.ID == nil { + return metav1.ConditionFalse, nil + } else { + return metav1.ConditionUnknown, nil + } + } + return metav1.ConditionTrue, nil +} + +func (addressscopeStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.AddressScopeResourceStatus(). + WithProjectID(osResource.ProjectID). + WithName(osResource.Name). + WithShared(osResource.Shared). + WithIPVersion(int32(osResource.IPVersion)) + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/addressscope/tests/addressscope-create-full/00-assert.yaml b/internal/controllers/addressscope/tests/addressscope-create-full/00-assert.yaml new file mode 100644 index 000000000..00cce7ced --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-full/00-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-create-full +status: + resource: + name: addressscope-create-full-override + ipVersion: 4 + shared: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-create-full + ref: addressscope + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: addressscope-create-full + ref: project +assertAll: + - celExpr: "addressscope.status.id != ''" + - celExpr: "addressscope.status.resource.projectID == project.status.id" diff --git a/internal/controllers/addressscope/tests/addressscope-create-full/00-create-resource.yaml b/internal/controllers/addressscope/tests/addressscope-create-full/00-create-resource.yaml new file mode 100644 index 000000000..cd6928ae9 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-full/00-create-resource.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: addressscope-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-create-full +spec: + cloudCredentialsRef: + # We need to use admin credentials to be able to create this + # AddressScope because we're specifying a different project + # that we are authenticated. + # https://docs.openstack.org/api-ref/network/v2/index.html#create-address-scope + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: addressscope-create-full-override + projectRef: addressscope-create-full + ipVersion: 4 + shared: true diff --git a/internal/controllers/addressscope/tests/addressscope-create-full/00-secret.yaml b/internal/controllers/addressscope/tests/addressscope-create-full/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-full/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-create-full/README.md b/internal/controllers/addressscope/tests/addressscope-create-full/README.md new file mode 100644 index 000000000..b1559172a --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-full/README.md @@ -0,0 +1,11 @@ +# Create an AddressScope with all the options + +## Step 00 + +Create an AddressScope using all available fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name from the spec when it is specified. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/addressscope/tests/addressscope-create-minimal/00-assert.yaml b/internal/controllers/addressscope/tests/addressscope-create-minimal/00-assert.yaml new file mode 100644 index 000000000..667713d5a --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-minimal/00-assert.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-create-minimal +status: + resource: + name: addressscope-create-minimal + ipVersion: 4 + shared: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-create-minimal + ref: addressscope +assertAll: + - celExpr: "addressscope.status.id != ''" + - celExpr: "addressscope.status.resource.projectID != ''" diff --git a/internal/controllers/addressscope/tests/addressscope-create-minimal/00-create-resource.yaml b/internal/controllers/addressscope/tests/addressscope-create-minimal/00-create-resource.yaml new file mode 100644 index 000000000..8e3f088e5 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-minimal/00-create-resource.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 diff --git a/internal/controllers/addressscope/tests/addressscope-create-minimal/00-secret.yaml b/internal/controllers/addressscope/tests/addressscope-create-minimal/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-minimal/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-create-minimal/01-assert.yaml b/internal/controllers/addressscope/tests/addressscope-create-minimal/01-assert.yaml new file mode 100644 index 000000000..99cd6caab --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-minimal/01-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: v1 + kind: Secret + name: openstack-clouds + ref: secret +assertAll: + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/addressscope' in secret.metadata.finalizers" diff --git a/internal/controllers/addressscope/tests/addressscope-create-minimal/01-delete-secret.yaml b/internal/controllers/addressscope/tests/addressscope-create-minimal/01-delete-secret.yaml new file mode 100644 index 000000000..1620791b9 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-minimal/01-delete-secret.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete secret openstack-clouds --wait=false + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-create-minimal/README.md b/internal/controllers/addressscope/tests/addressscope-create-minimal/README.md new file mode 100644 index 000000000..c60142ac7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-create-minimal/README.md @@ -0,0 +1,15 @@ +# Create an AddressScope with the minimum options + +## Step 00 + +Create a minimal AddressScope, that sets only the required fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified. + +## Step 01 + +Try deleting the secret and ensure that it is not deleted thanks to the finalizer. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/00-assert.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/00-assert.yaml new file mode 100644 index 000000000..f990e7ff8 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-dependency-no-secret +status: + conditions: + - type: Available + message: Waiting for Secret/addressscope-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/addressscope-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-dependency-no-project +status: + conditions: + - type: Available + message: Waiting for Project/addressscope-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Project/addressscope-dependency to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..e731f2549 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-dependency-no-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + projectRef: addressscope-dependency + ipVersion: 4 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-dependency-no-secret +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: addressscope-dependency + managementPolicy: managed + resource: + ipVersion: 4 diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/00-secret.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/01-assert.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/01-assert.yaml new file mode 100644 index 000000000..624cebf5e --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/01-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-dependency-no-secret +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-dependency-no-project +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/01-create-dependencies.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..6cd0d5040 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/01-create-dependencies.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic addressscope-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: addressscope-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/02-assert.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/02-assert.yaml new file mode 100644 index 000000000..4d3256dd3 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/02-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: addressscope-dependency + ref: project + - apiVersion: v1 + kind: Secret + name: addressscope-dependency + ref: secret +assertAll: + - celExpr: "project.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/addressscope' in project.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/addressscope' in secret.metadata.finalizers" diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/02-delete-dependencies.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/02-delete-dependencies.yaml new file mode 100644 index 000000000..178214e19 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/02-delete-dependencies.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete project.openstack.k-orc.cloud addressscope-dependency --wait=false + namespaced: true + - command: kubectl delete secret addressscope-dependency --wait=false + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/03-assert.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/03-assert.yaml new file mode 100644 index 000000000..7572987c2 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/03-assert.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get project.openstack.k-orc.cloud addressscope-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret addressscope-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/03-delete-resources.yaml b/internal/controllers/addressscope/tests/addressscope-dependency/03-delete-resources.yaml new file mode 100644 index 000000000..e07d5259f --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/03-delete-resources.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-dependency-no-project diff --git a/internal/controllers/addressscope/tests/addressscope-dependency/README.md b/internal/controllers/addressscope/tests/addressscope-dependency/README.md new file mode 100644 index 000000000..1637a8625 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-dependency/README.md @@ -0,0 +1,21 @@ +# Creation and deletion dependencies + +## Step 00 + +Create AddressScopes referencing non-existing resources. Each AddressScope is dependent on other non-existing resource. Verify that the AddressScopes are waiting for the needed resources to be created externally. + +## Step 01 + +Create the missing dependencies and verify all the AddressScopes are available. + +## Step 02 + +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 03 + +Delete the AddressScopes and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependency diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/00-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/00-assert.yaml new file mode 100644 index 000000000..dd3974f4f --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/00-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Project/addressscope-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Project/addressscope-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/00-import-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/00-import-resource.yaml new file mode 100644 index 000000000..f5e9a0b58 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/00-import-resource.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: addressscope-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: addressscope-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + projectRef: addressscope-import-dependency diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/00-secret.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/01-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/01-assert.yaml new file mode 100644 index 000000000..f961ee99d --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/01-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-dependency-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Project/addressscope-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Project/addressscope-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/01-create-trap-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/01-create-trap-resource.yaml new file mode 100644 index 000000000..0c8fcf0aa --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/01-create-trap-resource.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: addressscope-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# This `addressscope-import-dependency-not-this-one` should not be picked by the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 + projectRef: addressscope-import-dependency-not-this-one diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/02-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/02-assert.yaml new file mode 100644 index 000000000..5a71d805b --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/02-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-import-dependency + ref: addressscope1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-import-dependency-not-this-one + ref: addressscope2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: addressscope-import-dependency + ref: project +assertAll: + - celExpr: "addressscope1.status.id != addressscope2.status.id" + - celExpr: "addressscope1.status.resource.projectID == project.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-dependency +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/02-create-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/02-create-resource.yaml new file mode 100644 index 000000000..3ca9845d6 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/02-create-resource.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: addressscope-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 + projectRef: addressscope-import-dependency-external diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/03-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/03-assert.yaml new file mode 100644 index 000000000..183c12f03 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/03-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get project.openstack.k-orc.cloud addressscope-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/03-delete-import-dependencies.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/03-delete-import-dependencies.yaml new file mode 100644 index 000000000..cc2c952aa --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/03-delete-import-dependencies.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We should be able to delete the import dependencies + - command: kubectl delete project.openstack.k-orc.cloud addressscope-import-dependency + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/04-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/04-assert.yaml new file mode 100644 index 000000000..d8004f4db --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/04-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get addressscope.openstack.k-orc.cloud addressscope-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/04-delete-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import-dependency/04-delete-resource.yaml new file mode 100644 index 000000000..9dc761c63 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/04-delete-resource.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-import-dependency diff --git a/internal/controllers/addressscope/tests/addressscope-import-dependency/README.md b/internal/controllers/addressscope/tests/addressscope-import-dependency/README.md new file mode 100644 index 000000000..ce4b071ca --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-dependency/README.md @@ -0,0 +1,29 @@ +# Check dependency handling for imported AddressScope + +## Step 00 + +Import an AddressScope that references other imported resources. The referenced imported resources have no matching resources yet. +Verify the AddressScope is waiting for the dependency to be ready. + +## Step 01 + +Create an AddressScope matching the import filter, except for referenced resources, and verify that it's not being imported. + +## Step 02 + +Create the referenced resources and an AddressScope matching the import filters. + +Verify that the observed status on the imported AddressScope corresponds to the spec of the created AddressScope. + +## Step 03 + +Delete the referenced resources and check that ORC does not prevent deletion. The OpenStack resources still exist because they +were imported resources and we only deleted the ORC representation of it. + +## Step 04 + +Delete the AddressScope and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-dependency diff --git a/internal/controllers/addressscope/tests/addressscope-import-error/00-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import-error/00-assert.yaml new file mode 100644 index 000000000..a99503379 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-error/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-error-external-1 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-error-external-2 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/addressscope/tests/addressscope-import-error/00-create-resources.yaml b/internal/controllers/addressscope/tests/addressscope-import-error/00-create-resources.yaml new file mode 100644 index 000000000..775ce0239 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-error/00-create-resources.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-error-external-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-error-external-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 diff --git a/internal/controllers/addressscope/tests/addressscope-import-error/00-secret.yaml b/internal/controllers/addressscope/tests/addressscope-import-error/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-error/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-import-error/01-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import-error/01-assert.yaml new file mode 100644 index 000000000..c57c82729 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/addressscope/tests/addressscope-import-error/01-import-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import-error/01-import-resource.yaml new file mode 100644 index 000000000..c9073e8a6 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-error/01-import-resource.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-error +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + ipVersion: 4 diff --git a/internal/controllers/addressscope/tests/addressscope-import-error/README.md b/internal/controllers/addressscope/tests/addressscope-import-error/README.md new file mode 100644 index 000000000..338cf269f --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import-error/README.md @@ -0,0 +1,13 @@ +# Import AddressScope with more than one matching resources + +## Step 00 + +Create two AddressScopes with identical specs. + +## Step 01 + +Ensure that an imported AddressScope with a filter matching the resources returns an error. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error diff --git a/internal/controllers/addressscope/tests/addressscope-import/00-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import/00-assert.yaml new file mode 100644 index 000000000..d05edcda5 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/00-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/addressscope/tests/addressscope-import/00-import-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import/00-import-resource.yaml new file mode 100644 index 000000000..d25ab6f94 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/00-import-resource.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: addressscope-import-external + ipVersion: 4 + shared: true + diff --git a/internal/controllers/addressscope/tests/addressscope-import/00-secret.yaml b/internal/controllers/addressscope/tests/addressscope-import/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-import/01-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import/01-assert.yaml new file mode 100644 index 000000000..1f6fed6d5 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/01-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-external-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: addressscope-import-external-not-this-one + ipVersion: 4 + shared: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/addressscope/tests/addressscope-import/01-create-trap-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..cffc38ecd --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/01-create-trap-resource.yaml @@ -0,0 +1,16 @@ +--- +# This `addressscope-import-external-not-this-one` resource serves two purposes: +# - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) +# - ensure that importing a resource which name is a substring of it will not pick this one. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 + shared: true diff --git a/internal/controllers/addressscope/tests/addressscope-import/02-assert.yaml b/internal/controllers/addressscope/tests/addressscope-import/02-assert.yaml new file mode 100644 index 000000000..0e7ecfc38 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/02-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-import-external + ref: addressscope1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-import-external-not-this-one + ref: addressscope2 +assertAll: + - celExpr: "addressscope1.status.id != addressscope2.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: addressscope-import-external + ipVersion: 4 + shared: true diff --git a/internal/controllers/addressscope/tests/addressscope-import/02-create-resource.yaml b/internal/controllers/addressscope/tests/addressscope-import/02-create-resource.yaml new file mode 100644 index 000000000..3e81b0d9b --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/02-create-resource.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-import-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 + shared: true diff --git a/internal/controllers/addressscope/tests/addressscope-import/README.md b/internal/controllers/addressscope/tests/addressscope-import/README.md new file mode 100644 index 000000000..54359a58b --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-import/README.md @@ -0,0 +1,18 @@ +# Import AddressScope + +## Step 00 + +Import an addressscope that matches all fields in the filter, and verify it is waiting for the external resource to be created. + +## Step 01 + +Create an addressscope whose name is a superstring of the one specified in the import filter, otherwise matching the filter, and verify that it's not being imported. + +## Step 02 + +Create an addressscope matching the filter and verify that the observed status on the imported addressscope corresponds to the spec of the created addressscope. +Also, confirm that it does not adopt any addressscope whose name is a superstring of its own. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import diff --git a/internal/controllers/addressscope/tests/addressscope-update/00-assert.yaml b/internal/controllers/addressscope/tests/addressscope-update/00-assert.yaml new file mode 100644 index 000000000..5bf475fa1 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/00-assert.yaml @@ -0,0 +1,49 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-update + ref: addressscope + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-update-shared + ref: addressscopeShared +assertAll: + - celExpr: "addressscope.status.resource.projectID != ''" + - celExpr: "addressscopeShared.status.resource.projectID != ''" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update +status: + resource: + name: addressscope-update + ipVersion: 4 + shared: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update-shared +status: + resource: + name: addressscope-update-shared + ipVersion: 4 + shared: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/addressscope/tests/addressscope-update/00-minimal-resource.yaml b/internal/controllers/addressscope/tests/addressscope-update/00-minimal-resource.yaml new file mode 100644 index 000000000..bf3092497 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/00-minimal-resource.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 diff --git a/internal/controllers/addressscope/tests/addressscope-update/00-minimal-shared.yaml b/internal/controllers/addressscope/tests/addressscope-update/00-minimal-shared.yaml new file mode 100644 index 000000000..bf345b0bb --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/00-minimal-shared.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update-shared +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + ipVersion: 4 + shared: false diff --git a/internal/controllers/addressscope/tests/addressscope-update/00-secret.yaml b/internal/controllers/addressscope/tests/addressscope-update/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-update/01-assert.yaml b/internal/controllers/addressscope/tests/addressscope-update/01-assert.yaml new file mode 100644 index 000000000..ca3ae4d37 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/01-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update +status: + resource: + name: addressscope-update-updated + ipVersion: 4 + shared: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update-shared +status: + resource: + name: addressscope-update-shared + ipVersion: 4 + shared: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/addressscope/tests/addressscope-update/01-updated-resource.yaml b/internal/controllers/addressscope/tests/addressscope-update/01-updated-resource.yaml new file mode 100644 index 000000000..aefd7d703 --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/01-updated-resource.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update +spec: + resource: + name: addressscope-update-updated +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update-shared +spec: + resource: + shared: true diff --git a/internal/controllers/addressscope/tests/addressscope-update/02-assert.yaml b/internal/controllers/addressscope/tests/addressscope-update/02-assert.yaml new file mode 100644 index 000000000..d095fd69f --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/02-assert.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: AddressScope + name: addressscope-update + ref: addressscope +assertAll: + - celExpr: "addressscope.status.resource.projectID != ''" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: AddressScope +metadata: + name: addressscope-update +status: + resource: + name: addressscope-update + ipVersion: 4 + shared: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/addressscope/tests/addressscope-update/02-reverted-resource.yaml b/internal/controllers/addressscope/tests/addressscope-update/02-reverted-resource.yaml new file mode 100644 index 000000000..2c6c253ff --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/02-reverted-resource.yaml @@ -0,0 +1,7 @@ +# NOTE: kuttl only does patch updates, which means we can't delete a field. +# We have to use a kubectl apply command instead. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl replace -f 00-minimal-resource.yaml + namespaced: true diff --git a/internal/controllers/addressscope/tests/addressscope-update/README.md b/internal/controllers/addressscope/tests/addressscope-update/README.md new file mode 100644 index 000000000..8a88a9a3e --- /dev/null +++ b/internal/controllers/addressscope/tests/addressscope-update/README.md @@ -0,0 +1,18 @@ +# Update AddressScope + +## Step 00 + +Create two AddressScopes using only mandatory fields, but one of them +will be used to update the `shared` field. + +## Step 01 + +Update all mutable fields. + +## Step 02 + +Revert the resource to its original value and verify that the resulting object matches its state when first created, except the resource with the shared field. + +## Reference + +https://k-orc.cloud/development/writing-tests/#update diff --git a/internal/controllers/addressscope/zz_generated.adapter.go b/internal/controllers/addressscope/zz_generated.adapter.go new file mode 100644 index 000000000..5fb17a74d --- /dev/null +++ b/internal/controllers/addressscope/zz_generated.adapter.go @@ -0,0 +1,98 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addressscope + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.AddressScope + orcObjectListT = orcv1alpha1.AddressScopeList + resourceSpecT = orcv1alpha1.AddressScopeResourceSpec + filterT = orcv1alpha1.AddressScopeFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = addressscopeAdapter +) + +type addressscopeAdapter struct { + *orcv1alpha1.AddressScope +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.AddressScope +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return f.Status.ID +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.ID +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} + +// getResourceName returns the name of the OpenStack resource we should use. +// This method is not implemented as part of APIObjectAdapter as it is intended +// to be used by resource actuators, which don't use the adapter. +func getResourceName(orcObject orcObjectPT) string { + if orcObject.Spec.Resource.Name != nil { + return string(*orcObject.Spec.Resource.Name) + } + return orcObject.Name +} diff --git a/internal/controllers/addressscope/zz_generated.controller.go b/internal/controllers/addressscope/zz_generated.controller.go new file mode 100644 index 000000000..c17697f8c --- /dev/null +++ b/internal/controllers/addressscope/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package addressscope + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/controllers/applicationcredential/actuator.go b/internal/controllers/applicationcredential/actuator.go new file mode 100644 index 000000000..71989a676 --- /dev/null +++ b/internal/controllers/applicationcredential/actuator.go @@ -0,0 +1,297 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package applicationcredential + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/applicationcredentials" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// OpenStack resource types +type ( + osResourceT = applicationcredentials.ApplicationCredential + + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) + +type applicationcredentialActuator struct { + osClient osclients.ApplicationCredentialClient + k8sClient client.Client +} + +var _ createResourceActuator = applicationcredentialActuator{} +var _ deleteResourceActuator = applicationcredentialActuator{} + +func (applicationcredentialActuator) GetResourceID(osResource *osResourceT) string { + return osResource.ID +} + +func (actuator applicationcredentialActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) { + resource, err := actuator.osClient.GetApplicationCredential(ctx, id) + if err != nil { + return nil, progress.WrapError(err) + } + return resource, nil +} + +func (actuator applicationcredentialActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + user, _ := dependency.FetchDependency[*orcv1alpha1.User]( + ctx, actuator.k8sClient, orcObject.Namespace, + &resourceSpec.UserRef, "User", + orcv1alpha1.IsAvailable, + ) + + if user.Status.ID == nil { + return nil, false + } + + var filters []osclients.ResourceFilter[osResourceT] + + // Add client-side filters + if resourceSpec.Description != nil { + filters = append(filters, func(f *applicationcredentials.ApplicationCredential) bool { + return f.Description == *resourceSpec.Description + }) + } + + listOpts := applicationcredentials.ListOpts{ + Name: getResourceName(orcObject), + } + + return actuator.listOSResources(ctx, ptr.Deref(user.Status.ID, ""), filters, listOpts), true +} + +func (actuator applicationcredentialActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + user, rs := dependency.FetchDependency[*orcv1alpha1.User]( + ctx, actuator.k8sClient, obj.Namespace, + &filter.UserRef, "User", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + var filters []osclients.ResourceFilter[osResourceT] + + // Add client-side filters + if filter.Description != nil { + filters = append(filters, func(f *applicationcredentials.ApplicationCredential) bool { + return f.Description == *filter.Description + }) + } + + listOpts := applicationcredentials.ListOpts{ + Name: string(ptr.Deref(filter.Name, "")), + } + + return actuator.listOSResources(ctx, ptr.Deref(user.Status.ID, ""), filters, listOpts), nil +} + +func (actuator applicationcredentialActuator) listOSResources(ctx context.Context, userID string, filters []osclients.ResourceFilter[osResourceT], listOpts applicationcredentials.ListOptsBuilder) iter.Seq2[*applicationcredentials.ApplicationCredential, error] { + applicationCredentials := actuator.osClient.ListApplicationCredentials(ctx, userID, listOpts) + return osclients.Filter(applicationCredentials, filters...) +} + +func (actuator applicationcredentialActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + + var reconcileStatus progress.ReconcileStatus + + user, userDepRS := userDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + + rolesMap, roleDepRs := roleDependency.GetDependencies( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + + serviceMap, serviceDepRS := serviceDependency.GetDependencies( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + + secret, secretReconcileStatus := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, + &resource.SecretRef, "Secret", + func(*corev1.Secret) bool { return true }, // Secrets don't have availability status + ) + + var secretData []byte + if secretReconcileStatus == nil { + var ok bool + secretData, ok = secret.Data["value"] + if !ok { + reconcileStatus = reconcileStatus.WithReconcileStatus( + progress.NewReconcileStatus().WithProgressMessage("Application credential secret does not contain \"value\" key")) + } + } + + reconcileStatus = reconcileStatus. + WithReconcileStatus(userDepRS). + WithReconcileStatus(roleDepRs). + WithReconcileStatus(serviceDepRS). + WithReconcileStatus(secretReconcileStatus) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + roleList := make([]applicationcredentials.Role, len(resource.RoleRefs)) + for i := range resource.RoleRefs { + roleName := string(resource.RoleRefs[i]) + role, ok := rolesMap[roleName] + if !ok { + // Programming error + return nil, progress.WrapError(fmt.Errorf("role %s was not returned by GetDependencies", roleName)) + } + roleList[i].ID = *role.Status.ID + } + + accessRuleList := make([]applicationcredentials.AccessRule, len(resource.AccessRules)) + for i := range resource.AccessRules { + accessRuleSpec := &resource.AccessRules[i] + accessRule := &accessRuleList[i] + + if accessRuleSpec.ServiceRef != nil { + serviceName := string(*accessRuleSpec.ServiceRef) + service, ok := serviceMap[serviceName] + if !ok { + // Programming error + return nil, progress.WrapError(fmt.Errorf("service %s was not returned by GetDependencies", serviceName)) + } + accessRule.Service = service.Status.Resource.Type + } + + if accessRuleSpec.Path != nil { + accessRule.Path = *accessRuleSpec.Path + } + + if accessRuleSpec.Method != nil { + accessRule.Method = string(*accessRuleSpec.Method) + } + } + + createOpts := applicationcredentials.CreateOpts{ + Name: getResourceName(obj), + Description: ptr.Deref(resource.Description, ""), + Unrestricted: ptr.Deref(resource.Unrestricted, false), + Secret: string(secretData), + Roles: roleList, + AccessRules: accessRuleList, + } + + if resource.ExpiresAt != nil { + createOpts.ExpiresAt = &resource.ExpiresAt.Time + } + + osResource, err := actuator.osClient.CreateApplicationCredential(ctx, ptr.Deref(user.Status.ID, ""), createOpts) + if err != nil { + // We should require the spec to be updated before retrying a create which returned a conflict + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + return osResource, nil +} + +func (actuator applicationcredentialActuator) DeleteResource(ctx context.Context, orcObject orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + var reconcileStatus progress.ReconcileStatus + + user, userDepRS := userDependency.GetDependency( + ctx, actuator.k8sClient, orcObject, orcv1alpha1.IsAvailable, + ) + + reconcileStatus = reconcileStatus.WithReconcileStatus(userDepRS) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return reconcileStatus + } + + return progress.WrapError(actuator.osClient.DeleteApplicationCredential(ctx, ptr.Deref(user.Status.ID, ""), resource.ID)) +} + +type applicationcredentialHelperFactory struct{} + +var _ helperFactory = applicationcredentialHelperFactory{} + +func newActuator(ctx context.Context, orcObject *orcv1alpha1.ApplicationCredential, controller interfaces.ResourceController) (applicationcredentialActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, controller.GetK8sClient(), orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return applicationcredentialActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject) + if err != nil { + return applicationcredentialActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewApplicationCredentialClient() + if err != nil { + return applicationcredentialActuator{}, progress.WrapError(err) + } + + return applicationcredentialActuator{ + osClient: osClient, + k8sClient: controller.GetK8sClient(), + }, nil +} + +func (applicationcredentialHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { + return applicationcredentialAdapter{obj} +} + +func (applicationcredentialHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} + +func (applicationcredentialHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} diff --git a/internal/controllers/applicationcredential/controller.go b/internal/controllers/applicationcredential/controller.go new file mode 100644 index 000000000..c39cf1d47 --- /dev/null +++ b/internal/controllers/applicationcredential/controller.go @@ -0,0 +1,206 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package applicationcredential + +import ( + "context" + "errors" + "time" + + corev1 "k8s.io/api/core/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "applicationcredential" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=applicationcredentials,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=applicationcredentials/status,verbs=get;update;patch + +var ( + // We don't need a deletion guard on the application credential secret because it's only + // used on creation. + secretDependency = dependency.NewDependency[*orcv1alpha1.ApplicationCredentialList, *corev1.Secret]( + "spec.resource.secretRef", + func(applicationcredential *orcv1alpha1.ApplicationCredential) []string { + resource := applicationcredential.Spec.Resource + if resource == nil { + return nil + } + + return []string{string(resource.SecretRef)} + }, + ) + + roleDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ApplicationCredentialList, *orcv1alpha1.Role]( + "spec.resource.roleRefs", + func(applicationcredential *orcv1alpha1.ApplicationCredential) []string { + resource := applicationcredential.Spec.Resource + if resource == nil { + return nil + } + + roles := make([]string, len(resource.RoleRefs)) + for i := range resource.RoleRefs { + roles[i] = string(resource.RoleRefs[i]) + } + return roles + }, + finalizer, externalObjectFieldOwner, + ) + + serviceDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ApplicationCredentialList, *orcv1alpha1.Service]( + "spec.resource.accessRules[].serviceRef", + func(applicationcredential *orcv1alpha1.ApplicationCredential) []string { + resource := applicationcredential.Spec.Resource + if resource == nil { + return nil + } + + services := make([]string, 0) + for i := range resource.AccessRules { + if resource.AccessRules[i].ServiceRef == nil { + continue + } + services = append(services, string(*resource.AccessRules[i].ServiceRef)) + } + return services + }, + finalizer, externalObjectFieldOwner, + ) +) + +type applicationcredentialReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return &applicationcredentialReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (applicationcredentialReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *applicationcredentialReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var userDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ApplicationCredentialList, *orcv1alpha1.User]( + "spec.resource.userRef", + func(applicationcredential *orcv1alpha1.ApplicationCredential) []string { + resource := applicationcredential.Spec.Resource + if resource == nil { + return nil + } + return []string{string(resource.UserRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var userImportDependency = dependency.NewDependency[*orcv1alpha1.ApplicationCredentialList, *orcv1alpha1.User]( + "spec.import.filter.userRef", + func(applicationcredential *orcv1alpha1.ApplicationCredential) []string { + resource := applicationcredential.Spec.Import + if resource == nil || resource.Filter == nil { + return nil + } + return []string{string(resource.Filter.UserRef)} + }, +) + +// SetupWithManager sets up the controller with the Manager. +func (c *applicationcredentialReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + userWatchEventHandler, err := userDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + userImportWatchEventHandler, err := userImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + secretWatchEventHandler, err := secretDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + roleWatchEventHandler, err := roleDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + serviceWatchEventHandler, err := serviceDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + Watches(&orcv1alpha1.User{}, userWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.User{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.User{}, userImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.User{})), + ). + // XXX: This is a general watch on secrets. A general watch on secrets + // is undesirable because: + // - It requires problematic RBAC + // - Secrets are arbitrarily large, and we don't want to cache their contents + // + // These will require separate solutions. For the latter we should + // probably use a MetadataOnly watch only secrets. + Watches(&corev1.Secret{}, secretWatchEventHandler). + Watches(&orcv1alpha1.Role{}, roleWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Role{})), + ). + Watches(&orcv1alpha1.Service{}, serviceWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Service{})), + ). + For(&orcv1alpha1.ApplicationCredential{}) + + if err := errors.Join( + userDependency.AddToManager(ctx, mgr), + userImportDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + secretDependency.AddToManager(ctx, mgr), + roleDependency.AddToManager(ctx, mgr), + serviceDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, applicationcredentialHelperFactory{}, applicationcredentialStatusWriter{}, c.defaultResyncPeriod) + return builder.Complete(&r) +} diff --git a/internal/controllers/applicationcredential/status.go b/internal/controllers/applicationcredential/status.go new file mode 100644 index 000000000..2530a65e9 --- /dev/null +++ b/internal/controllers/applicationcredential/status.go @@ -0,0 +1,88 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package applicationcredential + +import ( + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type applicationcredentialStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.ApplicationCredentialApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.ApplicationCredentialStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.ApplicationCredential, *osResourceT, *objectApplyT, *statusApplyT] = applicationcredentialStatusWriter{} + +func (applicationcredentialStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.ApplicationCredential(name, namespace) +} + +func (applicationcredentialStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.ApplicationCredential, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource == nil { + if orcObject.Status.ID == nil { + return metav1.ConditionFalse, nil + } else { + return metav1.ConditionUnknown, nil + } + } + return metav1.ConditionTrue, nil +} + +func (applicationcredentialStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.ApplicationCredentialResourceStatus(). + WithName(osResource.Name). + WithUnrestricted(osResource.Unrestricted). + WithProjectID(osResource.ProjectID) + + if !osResource.ExpiresAt.IsZero() { + resourceStatus.WithExpiresAt(metav1.NewTime(osResource.ExpiresAt)) + } + + if osResource.Description != "" { + resourceStatus.WithDescription(osResource.Description) + } + + for i := range osResource.Roles { + roleStatus := orcapplyconfigv1alpha1.ApplicationCredentialRoleStatus(). + WithID(osResource.Roles[i].ID). + WithName(osResource.Roles[i].Name) + + if osResource.Roles[i].DomainID != "" { + roleStatus.WithDomainID(osResource.Roles[i].DomainID) + } + + resourceStatus.WithRoles(roleStatus) + } + + for i := range osResource.AccessRules { + accessRuleStatus := orcapplyconfigv1alpha1.ApplicationCredentialAccessRuleStatus(). + WithID(osResource.AccessRules[i].ID). + WithPath(osResource.AccessRules[i].Path). + WithMethod(osResource.AccessRules[i].Method). + WithService(osResource.AccessRules[i].Service) + + resourceStatus.WithAccessRules(accessRuleStatus) + } + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-assert.yaml new file mode 100644 index 000000000..917806d94 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-assert.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-create-full +status: + resource: + name: applicationcredential-create-full-override + description: ApplicationCredential from "create full" test + unrestricted: true + accessRules: + - method: "GET" + path: "/v2.1/servers" + service: "compute" + expiresAt: "2033-03-03T22:22:22Z" + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-create-full + ref: applicationcredential + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: applicationcredential-create-full + ref: user + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Role + name: applicationcredential-create-full + ref: role +assertAll: + - celExpr: "applicationcredential.status.id != ''" + - celExpr: "applicationcredential.status.resource.projectID != ''" + - celExpr: "applicationcredential.status.resource.accessRules.size() == 1" + - celExpr: "applicationcredential.status.resource.accessRules[0].id != ''" + - celExpr: "applicationcredential.status.resource.roles.size() == 1" + - celExpr: "applicationcredential.status.resource.roles[0].id == role.status.id" + - celExpr: "applicationcredential.status.resource.roles[0].name == role.status.resource.name" + - celExpr: "!has(applicationcredential.status.resource.roles[0].domainID)" diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-create-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-create-resource.yaml new file mode 100644 index 000000000..28b2c77d6 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-create-resource.yaml @@ -0,0 +1,62 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: applicationcredential-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: reader +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: applicationcredential-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + type: "compute" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: applicationcredential-create-full-override + description: ApplicationCredential from "create full" test + userRef: applicationcredential-create-full + unrestricted: true + secretRef: applicationcredential-secret + roleRefs: + - applicationcredential-create-full + accessRules: + - method: "GET" + serviceRef: applicationcredential-create-full + path: "/v2.1/servers" + expiresAt: "2033-03-03T22:22:22Z" diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-secret.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-secret.yaml new file mode 100644 index 000000000..fb6d508dd --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/00-secret.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - command: kubectl create secret generic applicationcredential-secret --from-literal=value=abc123 + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-full/README.md b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/README.md new file mode 100644 index 000000000..77afac10d --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-full/README.md @@ -0,0 +1,11 @@ +# Create a ApplicationCredential with all the options + +## Step 00 + +Create a ApplicationCredential using all available fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name from the spec when it is specified. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-assert.yaml new file mode 100644 index 000000000..a0e819eaa --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-assert.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-create-minimal +status: + resource: + # Name should default to object name + name: applicationcredential-create-minimal + unrestricted: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-create-minimal + ref: applicationcredential + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: applicationcredential-create-minimal + ref: user +assertAll: + - celExpr: "applicationcredential.status.id != ''" + - celExpr: "applicationcredential.status.resource.projectID != ''" + - celExpr: "!has(applicationcredential.status.resource.accessRules)" + - celExpr: "!has(applicationcredential.status.resource.description)" + - celExpr: "applicationcredential.status.resource.roles.size() >= 2" + - celExpr: "applicationcredential.status.resource.roles.exists(r, r.name == 'member')" + - celExpr: "applicationcredential.status.resource.roles.exists(r, r.name == 'reader')" diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-create-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-create-resource.yaml new file mode 100644 index 000000000..ac57fb94d --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-create-resource.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + userRef: applicationcredential-create-minimal + secretRef: applicationcredential-secret diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-secret.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-secret.yaml new file mode 100644 index 000000000..fb6d508dd --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/00-secret.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - command: kubectl create secret generic applicationcredential-secret --from-literal=value=abc123 + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/01-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/01-assert.yaml new file mode 100644 index 000000000..6362f0b10 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/01-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: v1 + kind: Secret + name: openstack-clouds + ref: secret +assertAll: + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/applicationcredential' in secret.metadata.finalizers" diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/01-delete-secret.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/01-delete-secret.yaml new file mode 100644 index 000000000..07f98457a --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/01-delete-secret.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete secret openstack-clouds --wait=false + namespaced: true + - command: kubectl delete secret applicationcredential-secret --wait=false + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/README.md b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/README.md new file mode 100644 index 000000000..79cd913b3 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-create-minimal/README.md @@ -0,0 +1,15 @@ +# Create a ApplicationCredential with the minimum options + +## Step 00 + +Create a minimal ApplicationCredential, that sets only the required fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified. + +## Step 01 + +Try deleting the secret and ensure that it is not deleted thanks to the finalizer. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-assert.yaml new file mode 100644 index 000000000..6416457dc --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-assert.yaml @@ -0,0 +1,75 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-secret +status: + conditions: + - type: Available + message: Waiting for Secret/applicationcredential-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/applicationcredential-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-secret-ref +status: + conditions: + - type: Available + message: Waiting for Secret/applicationcredential-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/applicationcredential-dependency-pending to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-user +status: + conditions: + - type: Available + message: Waiting for User/applicationcredential-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for User/applicationcredential-dependency-pending to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-role +status: + conditions: + - type: Available + message: Waiting for Role/applicationcredential-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Role/applicationcredential-dependency-pending to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-service +status: + conditions: + - type: Available + message: Waiting for Service/applicationcredential-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Service/applicationcredential-dependency-pending to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..4dacf814c --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,84 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-user +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + userRef: applicationcredential-dependency-pending + secretRef: applicationcredential-secret +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-secret +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: applicationcredential-dependency + managementPolicy: managed + resource: + userRef: applicationcredential-dependency + secretRef: applicationcredential-secret +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-secret-ref +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + userRef: applicationcredential-dependency + secretRef: applicationcredential-dependency-pending +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + userRef: applicationcredential-dependency + secretRef: applicationcredential-secret + roleRefs: + - applicationcredential-dependency-pending +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-service +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + userRef: applicationcredential-dependency + secretRef: applicationcredential-secret + accessRules: + - method: "GET" + serviceRef: applicationcredential-dependency-pending + path: "/v2.1/servers" diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-secret.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-secret.yaml new file mode 100644 index 000000000..fb6d508dd --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/00-secret.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - command: kubectl create secret generic applicationcredential-secret --from-literal=value=abc123 + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/01-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/01-assert.yaml new file mode 100644 index 000000000..42469b154 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/01-assert.yaml @@ -0,0 +1,75 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-secret +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-secret-ref +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-user +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-role +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-dependency-no-service +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/01-create-dependencies.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..360e7b670 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/01-create-dependencies.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic applicationcredential-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - command: kubectl create secret generic applicationcredential-dependency-pending --from-literal=value=abc123 + namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-dependency-pending +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: applicationcredential-dependency-pending +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: reader +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: applicationcredential-dependency-pending +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + type: "compute" diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/02-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/02-assert.yaml new file mode 100644 index 000000000..3c90253ef --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/02-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: applicationcredential-dependency + ref: user + - apiVersion: v1 + kind: Secret + name: applicationcredential-dependency + ref: secret +assertAll: + - celExpr: "user.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/applicationcredential' in user.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/applicationcredential' in secret.metadata.finalizers" diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/02-delete-dependencies.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/02-delete-dependencies.yaml new file mode 100644 index 000000000..8ff104281 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/02-delete-dependencies.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete user.openstack.k-orc.cloud applicationcredential-dependency --wait=false + namespaced: true + - command: kubectl delete secret applicationcredential-dependency --wait=false + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/03-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/03-assert.yaml new file mode 100644 index 000000000..4d6be7f09 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/03-assert.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get user.openstack.k-orc.cloud applicationcredential-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret applicationcredential-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/03-delete-resources.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/03-delete-resources.yaml new file mode 100644 index 000000000..1f8514050 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/03-delete-resources.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-dependency-no-user +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-dependency-no-secret-ref +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-dependency-no-role +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-dependency-no-service diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-dependency/README.md b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/README.md new file mode 100644 index 000000000..9d26de6a7 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-dependency/README.md @@ -0,0 +1,21 @@ +# Creation and deletion dependencies + +## Step 00 + +Create ApplicationCredentials referencing non-existing resources. Each ApplicationCredential is dependent on other non-existing resource. Verify that the ApplicationCredentials are waiting for the needed resources to be created externally. + +## Step 01 + +Create the missing dependencies and verify all the ApplicationCredentials are available. + +## Step 02 + +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 03 + +Delete the ApplicationCredentials and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependency diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-assert.yaml new file mode 100644 index 000000000..c9a2e3f75 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for User/applicationcredential-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for User/applicationcredential-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-import-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-import-resource.yaml new file mode 100644 index 000000000..8a871cea8 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-import-resource.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: applicationcredential-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + userRef: applicationcredential-import-dependency + description: applicationcredential-import-dependency-target diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-secret.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-secret.yaml new file mode 100644 index 000000000..b5bec8797 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/00-secret.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - command: kubectl create secret generic applicationcredential-secret --from-literal=value=abc123 + namespaced: true + - command: kubectl create secret generic applicationcredential-user-password --from-literal=password=abc123 + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/01-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/01-assert.yaml new file mode 100644 index 000000000..483ed5c58 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/01-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-dependency-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for User/applicationcredential-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for User/applicationcredential-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/01-create-trap-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/01-create-trap-resource.yaml new file mode 100644 index 000000000..bb5669bf5 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/01-create-trap-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +# This `applicationcredential-import-dependency-not-this-one` should not be picked by the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: applicationcredential-import-dependency-target + userRef: applicationcredential-import-dependency-not-this-one + secretRef: applicationcredential-secret diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/02-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/02-assert.yaml new file mode 100644 index 000000000..3c96a9fae --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/02-assert.yaml @@ -0,0 +1,34 @@ +--- +# FIXME: Need to be able to grant newly created external user permission to create application credentials +# apiVersion: kuttl.dev/v1beta1 +# kind: TestAssert +# resourceRefs: +# - apiVersion: openstack.k-orc.cloud/v1alpha1 +# kind: ApplicationCredential +# name: applicationcredential-import-dependency +# ref: applicationcredential1 +# - apiVersion: openstack.k-orc.cloud/v1alpha1 +# kind: ApplicationCredential +# name: applicationcredential-import-dependency-not-this-one +# ref: applicationcredential2 +# - apiVersion: openstack.k-orc.cloud/v1alpha1 +# kind: User +# name: applicationcredential-import-dependency +# ref: user +# assertAll: +# - celExpr: "applicationcredential1.status.id != applicationcredential2.status.id" +# # --- +# apiVersion: openstack.k-orc.cloud/v1alpha1 +# kind: ApplicationCredential +# metadata: +# name: applicationcredential-import-dependency +# status: +# conditions: +# - type: Available +# message: OpenStack resource is available +# status: "True" +# reason: Success +# - type: Progressing +# message: OpenStack resource is up to date +# status: "False" +# reason: Success diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/02-create-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/02-create-resource.yaml new file mode 100644 index 000000000..1a6b5cbd4 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/02-create-resource.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: applicationcredential external user + passwordRef: applicationcredential-user-password +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: applicationcredential-import-dependency-target + userRef: applicationcredential-import-dependency-external + secretRef: applicationcredential-secret diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/03-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/03-assert.yaml new file mode 100644 index 000000000..d74971a73 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/03-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get user.openstack.k-orc.cloud applicationcredential-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/03-delete-import-dependencies.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/03-delete-import-dependencies.yaml new file mode 100644 index 000000000..cc650c8c4 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/03-delete-import-dependencies.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We should be able to delete the import dependencies + - command: kubectl delete user.openstack.k-orc.cloud applicationcredential-import-dependency + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/04-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/04-assert.yaml new file mode 100644 index 000000000..4639c46a8 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/04-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get applicationcredential.openstack.k-orc.cloud applicationcredential-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/04-delete-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/04-delete-resource.yaml new file mode 100644 index 000000000..5a0b676bb --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/04-delete-resource.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-import-dependency diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/README.md b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/README.md new file mode 100644 index 000000000..2be49341d --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-dependency/README.md @@ -0,0 +1,29 @@ +# Check dependency handling for imported ApplicationCredential + +## Step 00 + +Import a ApplicationCredential that references other imported resources. The referenced imported resources have no matching resources yet. +Verify the ApplicationCredential is waiting for the dependency to be ready. + +## Step 01 + +Create a ApplicationCredential matching the import filter, except for referenced resources, and verify that it's not being imported. + +## Step 02 + +Create the referenced resources and a ApplicationCredential matching the import filters. + +Verify that the observed status on the imported ApplicationCredential corresponds to the spec of the created ApplicationCredential. + +## Step 03 + +Delete the referenced resources and check that ORC does not prevent deletion. The OpenStack resources still exist because they +were imported resources and we only deleted the ORC representation of it. + +## Step 04 + +Delete the ApplicationCredential and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-dependency diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-assert.yaml new file mode 100644 index 000000000..00afbdf41 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-error-external-1 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-error-external-2 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-create-resources.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-create-resources.yaml new file mode 100644 index 000000000..4422d1ca7 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-create-resources.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import-error +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-error-external-1 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ApplicationCredential from "import error" test + userRef: applicationcredential-import-error + secretRef: applicationcredential-secret +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-error-external-2 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ApplicationCredential from "import error" test + userRef: applicationcredential-import-error + secretRef: applicationcredential-secret diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-secret.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-secret.yaml new file mode 100644 index 000000000..fb6d508dd --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/00-secret.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - command: kubectl create secret generic applicationcredential-secret --from-literal=value=abc123 + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-error/01-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/01-assert.yaml new file mode 100644 index 000000000..e97dd9774 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-error/01-import-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/01-import-resource.yaml new file mode 100644 index 000000000..5cd837952 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/01-import-resource.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import-error +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-error +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + description: ApplicationCredential from "import error" test + userRef: applicationcredential-import-error diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import-error/README.md b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/README.md new file mode 100644 index 000000000..acd794097 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import-error/README.md @@ -0,0 +1,13 @@ +# Import ApplicationCredential with more than one matching resources + +## Step 00 + +Create two ApplicationCredentials with identical specs. + +## Step 01 + +Ensure that an imported ApplicationCredential with a filter matching the resources returns an error. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/00-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import/00-assert.yaml new file mode 100644 index 000000000..53ef7ac86 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/00-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/00-import-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import/00-import-resource.yaml new file mode 100644 index 000000000..39fbd4468 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/00-import-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: applicationcredential-import-external + description: ApplicationCredential applicationcredential-import-external from "applicationcredential-import" test + userRef: applicationcredential-import-external diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/00-secret.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import/00-secret.yaml new file mode 100644 index 000000000..fb6d508dd --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/00-secret.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - command: kubectl create secret generic applicationcredential-secret --from-literal=value=abc123 + namespaced: true diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/01-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import/01-assert.yaml new file mode 100644 index 000000000..1beb1c01c --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/01-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-external-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: applicationcredential-import-external-not-this-one + description: ApplicationCredential applicationcredential-import-external from "applicationcredential-import" test +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/01-create-trap-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..8af3547db --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/01-create-trap-resource.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +# This `applicationcredential-import-external-not-this-one` resource serves two purposes: +# - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) +# - ensure that importing a resource which name is a substring of it will not pick this one. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ApplicationCredential applicationcredential-import-external from "applicationcredential-import" test + userRef: applicationcredential-import-external-not-this-one + secretRef: applicationcredential-secret diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/02-assert.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import/02-assert.yaml new file mode 100644 index 000000000..7077e0834 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/02-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-import-external + ref: applicationcredential1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ApplicationCredential + name: applicationcredential-import-external-not-this-one + ref: applicationcredential2 +assertAll: + - celExpr: "applicationcredential1.status.id != applicationcredential2.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: applicationcredential-import-external + description: ApplicationCredential applicationcredential-import-external from "applicationcredential-import" test diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/02-create-resource.yaml b/internal/controllers/applicationcredential/tests/applicationcredential-import/02-create-resource.yaml new file mode 100644 index 000000000..3b9666b30 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/02-create-resource.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: applicationcredential-import +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: admin +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ApplicationCredential +metadata: + name: applicationcredential-import-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ApplicationCredential applicationcredential-import-external from "applicationcredential-import" test + userRef: applicationcredential-import + secretRef: applicationcredential-secret diff --git a/internal/controllers/applicationcredential/tests/applicationcredential-import/README.md b/internal/controllers/applicationcredential/tests/applicationcredential-import/README.md new file mode 100644 index 000000000..36422d1a4 --- /dev/null +++ b/internal/controllers/applicationcredential/tests/applicationcredential-import/README.md @@ -0,0 +1,18 @@ +# Import ApplicationCredential + +## Step 00 + +Import a applicationcredential that matches all fields in the filter, and verify it is waiting for the external resource to be created. + +## Step 01 + +Create a applicationcredential whose name is a superstring of the one specified in the import filter, otherwise matching the filter, and verify that it's not being imported. + +## Step 02 + +Create a applicationcredential matching the filter and verify that the observed status on the imported applicationcredential corresponds to the spec of the created applicationcredential. +Also, confirm that it does not adopt any applicationcredential whose name is a superstring of its own. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import diff --git a/internal/controllers/applicationcredential/zz_generated.adapter.go b/internal/controllers/applicationcredential/zz_generated.adapter.go new file mode 100644 index 000000000..d4f726aeb --- /dev/null +++ b/internal/controllers/applicationcredential/zz_generated.adapter.go @@ -0,0 +1,98 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package applicationcredential + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.ApplicationCredential + orcObjectListT = orcv1alpha1.ApplicationCredentialList + resourceSpecT = orcv1alpha1.ApplicationCredentialResourceSpec + filterT = orcv1alpha1.ApplicationCredentialFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = applicationcredentialAdapter +) + +type applicationcredentialAdapter struct { + *orcv1alpha1.ApplicationCredential +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.ApplicationCredential +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return f.Status.ID +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.ID +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} + +// getResourceName returns the name of the OpenStack resource we should use. +// This method is not implemented as part of APIObjectAdapter as it is intended +// to be used by resource actuators, which don't use the adapter. +func getResourceName(orcObject orcObjectPT) string { + if orcObject.Spec.Resource.Name != nil { + return string(*orcObject.Spec.Resource.Name) + } + return orcObject.Name +} diff --git a/internal/controllers/applicationcredential/zz_generated.controller.go b/internal/controllers/applicationcredential/zz_generated.controller.go new file mode 100644 index 000000000..09ae74111 --- /dev/null +++ b/internal/controllers/applicationcredential/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package applicationcredential + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/controllers/domain/actuator.go b/internal/controllers/domain/actuator.go index 968ddc990..d9653bcf0 100644 --- a/internal/controllers/domain/actuator.go +++ b/internal/controllers/domain/actuator.go @@ -144,12 +144,10 @@ func (actuator domainActuator) updateResource(ctx context.Context, obj orcObject _, err = actuator.osClient.UpdateDomain(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/domain/controller.go b/internal/controllers/domain/controller.go index 38c831aa2..6dfee5eb0 100644 --- a/internal/controllers/domain/controller.go +++ b/internal/controllers/domain/controller.go @@ -19,6 +19,7 @@ package domain import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -37,19 +38,24 @@ const controllerName = "domain" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=domains/status,verbs=get;update;patch type domainReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return domainReconcilerConstructor{scopeFactory: scopeFactory} + return &domainReconcilerConstructor{scopeFactory: scopeFactory} } func (domainReconcilerConstructor) GetName() string { return controllerName } +func (c *domainReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c domainReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *domainReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) builder := ctrl.NewControllerManagedBy(mgr). @@ -63,6 +69,6 @@ func (c domainReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, domainHelperFactory{}, domainStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, domainHelperFactory{}, domainStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/domain/zz_generated.adapter.go b/internal/controllers/domain/zz_generated.adapter.go index 89af22535..0a8c3b6ef 100644 --- a/internal/controllers/domain/zz_generated.adapter.go +++ b/internal/controllers/domain/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package domain import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/domain/zz_generated.controller.go b/internal/controllers/domain/zz_generated.controller.go index 31fd025a2..42194e684 100644 --- a/internal/controllers/domain/zz_generated.controller.go +++ b/internal/controllers/domain/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/endpoint/actuator.go b/internal/controllers/endpoint/actuator.go new file mode 100644 index 000000000..57d62f187 --- /dev/null +++ b/internal/controllers/endpoint/actuator.go @@ -0,0 +1,293 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package endpoint + +import ( + "context" + "iter" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/endpoints" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// OpenStack resource types +type ( + osResourceT = endpoints.Endpoint + + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + resourceReconciler = interfaces.ResourceReconciler[orcObjectPT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) + +type endpointActuator struct { + osClient osclients.EndpointClient + k8sClient client.Client +} + +var _ createResourceActuator = endpointActuator{} +var _ deleteResourceActuator = endpointActuator{} + +func (endpointActuator) GetResourceID(osResource *osResourceT) string { + return osResource.ID +} + +func (actuator endpointActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) { + resource, err := actuator.osClient.GetEndpoint(ctx, id) + if err != nil { + return nil, progress.WrapError(err) + } + return resource, nil +} + +func (actuator endpointActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + service, _ := serviceDependency.GetDependency( + ctx, actuator.k8sClient, orcObject, orcv1alpha1.IsAvailable, + ) + + if service == nil { + return nil, false + } + + filters := []osclients.ResourceFilter[osResourceT]{ + func(e *endpoints.Endpoint) bool { + return e.URL == resourceSpec.URL + }, + } + + listOpts := endpoints.ListOpts{ + Availability: gophercloud.Availability(resourceSpec.Interface), + ServiceID: ptr.Deref(service.Status.ID, ""), + } + + return actuator.listOsResources(ctx, listOpts, filters), true +} + +func (actuator endpointActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + service, rs := dependency.FetchDependency[*orcv1alpha1.Service]( + ctx, actuator.k8sClient, obj.Namespace, + filter.ServiceRef, "Service", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + var resourceFilters []osclients.ResourceFilter[osResourceT] + if filter.URL != "" { + resourceFilters = append(resourceFilters, func(e *endpoints.Endpoint) bool { + return e.URL == filter.URL + }) + } + + listOpts := endpoints.ListOpts{ + ServiceID: ptr.Deref(service.Status.ID, ""), + Availability: gophercloud.Availability(filter.Interface), + } + + return actuator.listOsResources(ctx, listOpts, resourceFilters), nil +} + +func (actuator endpointActuator) listOsResources(ctx context.Context, listOpts endpoints.ListOpts, filter []osclients.ResourceFilter[osResourceT]) iter.Seq2[*osResourceT, error] { + endpoints := actuator.osClient.ListEndpoints(ctx, listOpts) + return osclients.Filter(endpoints, filter...) +} + +func (actuator endpointActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + var reconcileStatus progress.ReconcileStatus + + var serviceID string + service, serviceDepRS := serviceDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + + reconcileStatus = reconcileStatus.WithReconcileStatus(serviceDepRS) + if service != nil { + serviceID = ptr.Deref(service.Status.ID, "") + } + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + createOpts := endpoints.CreateOpts{ + Availability: gophercloud.Availability(resource.Interface), + Description: ptr.Deref(resource.Description, ""), + Enabled: resource.Enabled, + ServiceID: serviceID, + URL: resource.URL, + } + + osResource, err := actuator.osClient.CreateEndpoint(ctx, createOpts) + if err != nil { + // We should require the spec to be updated before retrying a create which returned a conflict + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + return osResource, nil +} + +func (actuator endpointActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + return progress.WrapError(actuator.osClient.DeleteEndpoint(ctx, resource.ID)) +} + +func (actuator endpointActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + // Should have been caught by API validation + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + + updateOpts := endpoints.UpdateOpts{} + + handleEnabledUpdate(&updateOpts, resource, osResource) + handleURLUpdate(&updateOpts, resource, osResource) + handleInterfaceUpdate(&updateOpts, resource, osResource) + + needsUpdate, err := needsUpdate(updateOpts) + if err != nil { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err)) + } + if !needsUpdate { + log.V(logging.Debug).Info("No changes") + return nil + } + + _, err = actuator.osClient.UpdateEndpoint(ctx, osResource.ID, updateOpts) + + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) + } + + return progress.NeedsRefresh() +} + +func needsUpdate(updateOpts endpoints.UpdateOpts) (bool, error) { + updateOptsMap, err := updateOpts.ToEndpointUpdateMap() + if err != nil { + return false, err + } + + updateMap, ok := updateOptsMap["endpoint"].(map[string]any) + if !ok { + updateMap = make(map[string]any) + } + + return len(updateMap) > 0, nil +} + +func handleURLUpdate(updateOpts *endpoints.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + url := resource.URL + if osResource.URL != url { + updateOpts.URL = url + } +} + +func handleInterfaceUpdate(updateOpts *endpoints.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + endpointInterface := gophercloud.Availability(resource.Interface) + if osResource.Availability != endpointInterface { + updateOpts.Availability = endpointInterface + } +} + +func handleEnabledUpdate(updateOpts *endpoints.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + enabled := resource.Enabled + if enabled != nil && osResource.Enabled != *enabled { + updateOpts.Enabled = enabled + } +} + +func (actuator endpointActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.updateResource, + }, nil +} + +type endpointHelperFactory struct{} + +var _ helperFactory = endpointHelperFactory{} + +func newActuator(ctx context.Context, orcObject *orcv1alpha1.Endpoint, controller interfaces.ResourceController) (endpointActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, controller.GetK8sClient(), orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return endpointActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject) + if err != nil { + return endpointActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewEndpointClient() + if err != nil { + return endpointActuator{}, progress.WrapError(err) + } + + return endpointActuator{ + osClient: osClient, + k8sClient: controller.GetK8sClient(), + }, nil +} + +func (endpointHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { + return endpointAdapter{obj} +} + +func (endpointHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} + +func (endpointHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} diff --git a/internal/controllers/endpoint/actuator_test.go b/internal/controllers/endpoint/actuator_test.go new file mode 100644 index 000000000..e15f8ee50 --- /dev/null +++ b/internal/controllers/endpoint/actuator_test.go @@ -0,0 +1,112 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package endpoint + +import ( + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/endpoints" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "k8s.io/utils/ptr" +) + +func TestNeedsUpdate(t *testing.T) { + testCases := []struct { + name string + updateOpts endpoints.UpdateOpts + expectChange bool + }{ + { + name: "Empty base opts", + updateOpts: endpoints.UpdateOpts{}, + expectChange: false, + }, + { + name: "Updated opts", + updateOpts: endpoints.UpdateOpts{URL: "http://updated.com"}, + expectChange: true, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + got, _ := needsUpdate(tt.updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestHandleInterfaceUpdate(t *testing.T) { + testCases := []struct { + name string + newValue *string + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptr.To("internal"), existingValue: "internal", expectChange: false}, + {name: "Different", newValue: ptr.To("public"), existingValue: "internal", expectChange: true}, + {name: "No value provided, existing is kept", newValue: nil, existingValue: "internal", expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resourceSpec := &orcv1alpha1.EndpointResourceSpec{Interface: ptr.Deref(tt.newValue, "")} + osResource := &osResourceT{Availability: gophercloud.Availability(tt.existingValue)} + + updateOpts := endpoints.UpdateOpts{} + handleInterfaceUpdate(&updateOpts, resourceSpec, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleURLUpdate(t *testing.T) { + testCases := []struct { + name string + newValue *string + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptr.To("http://same.com"), existingValue: "http://same.com", expectChange: false}, + {name: "Different", newValue: ptr.To("http://different.com"), existingValue: "http://same.com", expectChange: true}, + {name: "No value provided, existing is kept", newValue: nil, existingValue: "http://same.com", expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resourceSpec := &orcv1alpha1.EndpointResourceSpec{URL: ptr.Deref(tt.newValue, "")} + osResource := &osResourceT{URL: tt.existingValue} + + updateOpts := endpoints.UpdateOpts{} + handleURLUpdate(&updateOpts, resourceSpec, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} diff --git a/internal/controllers/endpoint/controller.go b/internal/controllers/endpoint/controller.go new file mode 100644 index 000000000..727cb1025 --- /dev/null +++ b/internal/controllers/endpoint/controller.go @@ -0,0 +1,120 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package endpoint + +import ( + "context" + "errors" + "time" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "endpoint" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=endpoints,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=endpoints/status,verbs=get;update;patch + +type endpointReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return &endpointReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (endpointReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *endpointReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var serviceDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.EndpointList, *orcv1alpha1.Service]( + "spec.resource.serviceRef", + func(endpoint *orcv1alpha1.Endpoint) []string { + resource := endpoint.Spec.Resource + if resource == nil { + return nil + } + return []string{string(resource.ServiceRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var serviceImportDependency = dependency.NewDependency[*orcv1alpha1.EndpointList, *orcv1alpha1.Service]( + "spec.import.filter.serviceRef", + func(endpoint *orcv1alpha1.Endpoint) []string { + resource := endpoint.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.ServiceRef == nil { + return nil + } + return []string{string(*resource.Filter.ServiceRef)} + }, +) + +// SetupWithManager sets up the controller with the Manager. +func (c *endpointReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + serviceWatchEventHandler, err := serviceDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + serviceImportWatchEventHandler, err := serviceImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + Watches(&orcv1alpha1.Service{}, serviceWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Service{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Service{}, serviceImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Service{})), + ). + For(&orcv1alpha1.Endpoint{}) + + if err := errors.Join( + serviceDependency.AddToManager(ctx, mgr), + serviceImportDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, endpointHelperFactory{}, endpointStatusWriter{}, c.defaultResyncPeriod) + return builder.Complete(&r) +} diff --git a/internal/controllers/endpoint/status.go b/internal/controllers/endpoint/status.go new file mode 100644 index 000000000..e3f285724 --- /dev/null +++ b/internal/controllers/endpoint/status.go @@ -0,0 +1,63 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package endpoint + +import ( + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type endpointStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.EndpointApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.EndpointStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.Endpoint, *osResourceT, *objectApplyT, *statusApplyT] = endpointStatusWriter{} + +func (endpointStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.Endpoint(name, namespace) +} + +func (endpointStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.Endpoint, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource == nil { + if orcObject.Status.ID == nil { + return metav1.ConditionFalse, nil + } else { + return metav1.ConditionUnknown, nil + } + } + return metav1.ConditionTrue, nil +} + +func (endpointStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.EndpointResourceStatus(). + WithServiceID(osResource.ServiceID). + WithEnabled(osResource.Enabled). + WithInterface(string(osResource.Availability)). + WithURL(osResource.URL) + + if osResource.Description != "" { + resourceStatus.WithDescription(osResource.Description) + } + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/endpoint/tests/endpoint-create-full/00-assert.yaml b/internal/controllers/endpoint/tests/endpoint-create-full/00-assert.yaml new file mode 100644 index 000000000..0c962cfe7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-full/00-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-create-full +status: + resource: + description: "Endpoint description" + interface: internal + url: https://example.com + enabled: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-create-full + ref: endpoint + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: endpoint-create-full + ref: service +assertAll: + - celExpr: "endpoint.status.id != ''" + - celExpr: "endpoint.status.resource.serviceID == service.status.id" + - celExpr: "!has(endpoint.status.resource.name)" diff --git a/internal/controllers/endpoint/tests/endpoint-create-full/00-create-resource.yaml b/internal/controllers/endpoint/tests/endpoint-create-full/00-create-resource.yaml new file mode 100644 index 000000000..aa7360418 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-full/00-create-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-test +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: "Endpoint description" + serviceRef: endpoint-create-full + interface: internal + url: https://example.com + enabled: false diff --git a/internal/controllers/endpoint/tests/endpoint-create-full/00-secret.yaml b/internal/controllers/endpoint/tests/endpoint-create-full/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-full/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-create-full/README.md b/internal/controllers/endpoint/tests/endpoint-create-full/README.md new file mode 100644 index 000000000..2f771930b --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-full/README.md @@ -0,0 +1,11 @@ +# Create an Endpoint with all the options + +## Step 00 + +Create an Endpoint using all available fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name from the spec when it is specified. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/endpoint/tests/endpoint-create-minimal/00-assert.yaml b/internal/controllers/endpoint/tests/endpoint-create-minimal/00-assert.yaml new file mode 100644 index 000000000..3924e2cf7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-minimal/00-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-create-minimal +status: + resource: + url: http://example.com + interface: internal + enabled: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-create-minimal + ref: endpoint + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: endpoint-create-minimal + ref: service +assertAll: + - celExpr: "endpoint.status.id != ''" + - celExpr: "endpoint.status.resource.serviceID == service.status.id" + - celExpr: "!has(endpoint.status.resource.name)" diff --git a/internal/controllers/endpoint/tests/endpoint-create-minimal/00-create-resource.yaml b/internal/controllers/endpoint/tests/endpoint-create-minimal/00-create-resource.yaml new file mode 100644 index 000000000..48b59dc12 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-minimal/00-create-resource.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-test +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-create-minimal + interface: internal + url: http://example.com diff --git a/internal/controllers/endpoint/tests/endpoint-create-minimal/00-secret.yaml b/internal/controllers/endpoint/tests/endpoint-create-minimal/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-minimal/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-create-minimal/01-assert.yaml b/internal/controllers/endpoint/tests/endpoint-create-minimal/01-assert.yaml new file mode 100644 index 000000000..e724dcbaa --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-minimal/01-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: v1 + kind: Secret + name: openstack-clouds + ref: secret +assertAll: + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/endpoint' in secret.metadata.finalizers" diff --git a/internal/controllers/endpoint/tests/endpoint-create-minimal/01-delete-secret.yaml b/internal/controllers/endpoint/tests/endpoint-create-minimal/01-delete-secret.yaml new file mode 100644 index 000000000..1620791b9 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-minimal/01-delete-secret.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete secret openstack-clouds --wait=false + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-create-minimal/README.md b/internal/controllers/endpoint/tests/endpoint-create-minimal/README.md new file mode 100644 index 000000000..4deb31e1b --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-create-minimal/README.md @@ -0,0 +1,15 @@ +# Create an Endpoint with the minimum options + +## Step 00 + +Create a minimal Endpoint, that sets only the required fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified. + +## Step 01 + +Try deleting the secret and ensure that it is not deleted thanks to the finalizer. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/00-assert.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/00-assert.yaml new file mode 100644 index 000000000..d38283ca6 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-dependency-no-secret +status: + conditions: + - type: Available + message: Waiting for Secret/endpoint-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/endpoint-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-dependency-no-service +status: + conditions: + - type: Available + message: Waiting for Service/endpoint-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Service/endpoint-dependency-pending to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..625057953 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-test +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-dependency-no-service +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-dependency-pending + interface: internal + url: http://example.com +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-dependency-no-secret +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: endpoint-dependency + managementPolicy: managed + resource: + serviceRef: endpoint-dependency + interface: internal + url: http://example.com diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/00-secret.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/01-assert.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/01-assert.yaml new file mode 100644 index 000000000..c0c5097dd --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/01-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-dependency-no-secret +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-dependency-no-service +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/01-create-dependencies.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..103c5b682 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/01-create-dependencies.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic endpoint-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-dependency-pending +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-test diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/02-assert.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/02-assert.yaml new file mode 100644 index 000000000..8dbeb3371 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/02-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: endpoint-dependency + ref: service + - apiVersion: v1 + kind: Secret + name: endpoint-dependency + ref: secret +assertAll: + - celExpr: "service.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/endpoint' in service.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/endpoint' in secret.metadata.finalizers" diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/02-delete-dependencies.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/02-delete-dependencies.yaml new file mode 100644 index 000000000..67c2751dd --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/02-delete-dependencies.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete service.openstack.k-orc.cloud endpoint-dependency --wait=false + namespaced: true + - command: kubectl delete secret endpoint-dependency --wait=false + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/03-assert.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/03-assert.yaml new file mode 100644 index 000000000..6526468ad --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/03-assert.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get service.openstack.k-orc.cloud endpoint-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret endpoint-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/03-delete-resources.yaml b/internal/controllers/endpoint/tests/endpoint-dependency/03-delete-resources.yaml new file mode 100644 index 000000000..89be93a7b --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/03-delete-resources.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-dependency-no-service diff --git a/internal/controllers/endpoint/tests/endpoint-dependency/README.md b/internal/controllers/endpoint/tests/endpoint-dependency/README.md new file mode 100644 index 000000000..34cbddcda --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-dependency/README.md @@ -0,0 +1,21 @@ +# Creation and deletion dependencies + +## Step 00 + +Create Endpoints referencing non-existing resources. Each Endpoint is dependent on other non-existing resource. Verify that the Endpoints are waiting for the needed resources to be created externally. + +## Step 01 + +Create the missing dependencies and verify all the Endpoints are available. + +## Step 02 + +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 03 + +Delete the Endpoints and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependency diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/00-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/00-assert.yaml new file mode 100644 index 000000000..17743d6e9 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/00-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Service/endpoint-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Service/endpoint-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/00-import-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/00-import-resource.yaml new file mode 100644 index 000000000..76cddcd65 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/00-import-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: endpoint-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + serviceRef: endpoint-import-dependency + interface: internal + url: http://example.com diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/00-secret.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/01-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/01-assert.yaml new file mode 100644 index 000000000..438dd019a --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/01-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-dependency-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Service/endpoint-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Service/endpoint-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/01-create-trap-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/01-create-trap-resource.yaml new file mode 100644 index 000000000..a7c71eceb --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/01-create-trap-resource.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-import-dependency-not-this-one +--- +# This `endpoint-import-dependency-not-this-one` should not be picked by the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-import-dependency-not-this-one + interface: internal + url: http://example.com diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/02-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/02-assert.yaml new file mode 100644 index 000000000..76b42d4b6 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/02-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-import-dependency + ref: endpoint1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-import-dependency-not-this-one + ref: endpoint2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: endpoint-import-dependency + ref: service +assertAll: + - celExpr: "endpoint1.status.id != endpoint2.status.id" + - celExpr: "endpoint1.status.resource.serviceID == service.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-dependency +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/02-create-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/02-create-resource.yaml new file mode 100644 index 000000000..65786fa03 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/02-create-resource.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-import-dependency-external + interface: internal + url: http://example.com diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/03-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/03-assert.yaml new file mode 100644 index 000000000..3d5d36d5e --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/03-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get service.openstack.k-orc.cloud endpoint-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/03-delete-import-dependencies.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/03-delete-import-dependencies.yaml new file mode 100644 index 000000000..df9a4359c --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/03-delete-import-dependencies.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We should be able to delete the import dependencies + - command: kubectl delete service.openstack.k-orc.cloud endpoint-import-dependency + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/04-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/04-assert.yaml new file mode 100644 index 000000000..108f72ce3 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/04-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get endpoint.openstack.k-orc.cloud endpoint-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/04-delete-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import-dependency/04-delete-resource.yaml new file mode 100644 index 000000000..56a973e5b --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/04-delete-resource.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-import-dependency diff --git a/internal/controllers/endpoint/tests/endpoint-import-dependency/README.md b/internal/controllers/endpoint/tests/endpoint-import-dependency/README.md new file mode 100644 index 000000000..8395dc34a --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-dependency/README.md @@ -0,0 +1,29 @@ +# Check dependency handling for imported Endpoint + +## Step 00 + +Import an Endpoint that references other imported resources. The referenced imported resources have no matching resources yet. +Verify the Endpoint is waiting for the dependency to be ready. + +## Step 01 + +Create an Endpoint matching the import filter, except for referenced resources, and verify that it's not being imported. + +## Step 02 + +Create the referenced resources and an Endpoint matching the import filters. + +Verify that the observed status on the imported Endpoint corresponds to the spec of the created Endpoint. + +## Step 03 + +Delete the referenced resources and check that ORC does not prevent deletion. The OpenStack resources still exist because they +were imported resources and we only deleted the ORC representation of it. + +## Step 04 + +Delete the Endpoint and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-dependency diff --git a/internal/controllers/endpoint/tests/endpoint-import-error/00-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import-error/00-assert.yaml new file mode 100644 index 000000000..06992d40e --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-error/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-error-external-1 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-error-external-2 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/endpoint/tests/endpoint-import-error/00-create-resources.yaml b/internal/controllers/endpoint/tests/endpoint-import-error/00-create-resources.yaml new file mode 100644 index 000000000..43afeab6f --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-error/00-create-resources.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-import-error +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-import-error +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-error-external-1 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-import-error + interface: internal + url: http://example1.com +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-error-external-2 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-import-error + interface: internal + url: http://example2.com diff --git a/internal/controllers/endpoint/tests/endpoint-import-error/00-secret.yaml b/internal/controllers/endpoint/tests/endpoint-import-error/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-error/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-import-error/01-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import-error/01-assert.yaml new file mode 100644 index 000000000..e9751d908 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/endpoint/tests/endpoint-import-error/01-import-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import-error/01-import-resource.yaml new file mode 100644 index 000000000..0b106e2cd --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-error/01-import-resource.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-error +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + serviceRef: endpoint-import-error + interface: internal diff --git a/internal/controllers/endpoint/tests/endpoint-import-error/README.md b/internal/controllers/endpoint/tests/endpoint-import-error/README.md new file mode 100644 index 000000000..7a8e80bcf --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import-error/README.md @@ -0,0 +1,13 @@ +# Import Endpoint with more than one matching resources + +## Step 00 + +Create two Endpoints with identical specs. + +## Step 01 + +Ensure that an imported Endpoint with a filter matching the resources returns an error. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error diff --git a/internal/controllers/endpoint/tests/endpoint-import/00-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import/00-assert.yaml new file mode 100644 index 000000000..cc87b9a8e --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/00-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/endpoint/tests/endpoint-import/00-import-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import/00-import-resource.yaml new file mode 100644 index 000000000..e42eeedd3 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/00-import-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-import +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-import +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + serviceRef: endpoint-import + interface: internal + url: http://example.com + enabled: false diff --git a/internal/controllers/endpoint/tests/endpoint-import/00-secret.yaml b/internal/controllers/endpoint/tests/endpoint-import/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-import/01-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import/01-assert.yaml new file mode 100644 index 000000000..a7983cc2c --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/01-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-external-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + interface: internal + url: http://example.com +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/endpoint/tests/endpoint-import/01-create-trap-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..b788e3f82 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/01-create-trap-resource.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-import-external-not-this-one +--- +# This `endpoint-import-external-not-this-one` resource serves two purposes: +# - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) +# - ensure that importing a resource which name is a substring of it will not pick this one. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-import-external-not-this-one + interface: internal + url: http://example.com diff --git a/internal/controllers/endpoint/tests/endpoint-import/02-assert.yaml b/internal/controllers/endpoint/tests/endpoint-import/02-assert.yaml new file mode 100644 index 000000000..a776882ab --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/02-assert.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-import-external + ref: endpoint1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-import-external-not-this-one + ref: endpoint2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: endpoint-import + ref: service +assertAll: + - celExpr: "endpoint1.status.id != endpoint2.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + interface: internal + url: http://example.com + enabled: false diff --git a/internal/controllers/endpoint/tests/endpoint-import/02-create-resource.yaml b/internal/controllers/endpoint/tests/endpoint-import/02-create-resource.yaml new file mode 100644 index 000000000..499ff7783 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/02-create-resource.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-import-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-import + interface: internal + url: http://example.com + enabled: false diff --git a/internal/controllers/endpoint/tests/endpoint-import/README.md b/internal/controllers/endpoint/tests/endpoint-import/README.md new file mode 100644 index 000000000..41257fe8c --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-import/README.md @@ -0,0 +1,18 @@ +# Import Endpoint + +## Step 00 + +Import an endpoint that matches all fields in the filter, and verify it is waiting for the external resource to be created. + +## Step 01 + +Create an endpoint whose name is a superstring of the one specified in the import filter, otherwise matching the filter, and verify that it's not being imported. + +## Step 02 + +Create an endpoint matching the filter and verify that the observed status on the imported endpoint corresponds to the spec of the created endpoint. +Also, confirm that it does not adopt any endpoint whose name is a superstring of its own. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import diff --git a/internal/controllers/endpoint/tests/endpoint-update/00-assert.yaml b/internal/controllers/endpoint/tests/endpoint-update/00-assert.yaml new file mode 100644 index 000000000..0714459c2 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/00-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-update +status: + resource: + interface: internal + url: http://example.com + enabled: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-update + ref: endpoint + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: endpoint-update + ref: service +assertAll: + - celExpr: "endpoint.status.resource.serviceID == service.status.id" + - celExpr: "!has(endpoint.status.resource.name)" + - celExpr: "!has(endpoint.status.resource.description)" diff --git a/internal/controllers/endpoint/tests/endpoint-update/00-minimal-resource.yaml b/internal/controllers/endpoint/tests/endpoint-update/00-minimal-resource.yaml new file mode 100644 index 000000000..535c94d1a --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/00-minimal-resource.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: endpoint-update +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: endpoint-test-update +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-update +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: endpoint-update + interface: internal + url: http://example.com + # Set a different value than the default so we can update it + # later. + enabled: false diff --git a/internal/controllers/endpoint/tests/endpoint-update/00-secret.yaml b/internal/controllers/endpoint/tests/endpoint-update/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-update/01-assert.yaml b/internal/controllers/endpoint/tests/endpoint-update/01-assert.yaml new file mode 100644 index 000000000..4d03c34d6 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/01-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-update +status: + resource: + interface: public + url: http://example.com/updated + enabled: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/endpoint/tests/endpoint-update/01-updated-resource.yaml b/internal/controllers/endpoint/tests/endpoint-update/01-updated-resource.yaml new file mode 100644 index 000000000..c95d344e3 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/01-updated-resource.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-update +spec: + resource: + interface: public + url: http://example.com/updated + enabled: true diff --git a/internal/controllers/endpoint/tests/endpoint-update/02-assert.yaml b/internal/controllers/endpoint/tests/endpoint-update/02-assert.yaml new file mode 100644 index 000000000..f41c5016e --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/02-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Endpoint + name: endpoint-update + ref: endpoint + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: endpoint-update + ref: service +assertAll: + - celExpr: "endpoint.status.resource.serviceID == service.status.id" + - celExpr: "!has(endpoint.status.resource.name)" + - celExpr: "!has(endpoint.status.resource.description)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Endpoint +metadata: + name: endpoint-update +status: + resource: + interface: internal + url: http://example.com + enabled: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/endpoint/tests/endpoint-update/02-reverted-resource.yaml b/internal/controllers/endpoint/tests/endpoint-update/02-reverted-resource.yaml new file mode 100644 index 000000000..2c6c253ff --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/02-reverted-resource.yaml @@ -0,0 +1,7 @@ +# NOTE: kuttl only does patch updates, which means we can't delete a field. +# We have to use a kubectl apply command instead. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl replace -f 00-minimal-resource.yaml + namespaced: true diff --git a/internal/controllers/endpoint/tests/endpoint-update/README.md b/internal/controllers/endpoint/tests/endpoint-update/README.md new file mode 100644 index 000000000..342914f80 --- /dev/null +++ b/internal/controllers/endpoint/tests/endpoint-update/README.md @@ -0,0 +1,17 @@ +# Update Endpoint + +## Step 00 + +Create an Endpoint using only mandatory fields. + +## Step 01 + +Update all mutable fields. + +## Step 02 + +Revert the resource to its original value and verify that the resulting object matches its state when first created. + +## Reference + +https://k-orc.cloud/development/writing-tests/#update diff --git a/internal/controllers/endpoint/zz_generated.adapter.go b/internal/controllers/endpoint/zz_generated.adapter.go new file mode 100644 index 000000000..b5b462573 --- /dev/null +++ b/internal/controllers/endpoint/zz_generated.adapter.go @@ -0,0 +1,88 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package endpoint + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.Endpoint + orcObjectListT = orcv1alpha1.EndpointList + resourceSpecT = orcv1alpha1.EndpointResourceSpec + filterT = orcv1alpha1.EndpointFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = endpointAdapter +) + +type endpointAdapter struct { + *orcv1alpha1.Endpoint +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.Endpoint +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return f.Status.ID +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.ID +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} diff --git a/internal/controllers/endpoint/zz_generated.controller.go b/internal/controllers/endpoint/zz_generated.controller.go new file mode 100644 index 000000000..e0ccac2f9 --- /dev/null +++ b/internal/controllers/endpoint/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package endpoint + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/controllers/flavor/actuator.go b/internal/controllers/flavor/actuator.go index 16eb9c73b..d34cf09fc 100644 --- a/internal/controllers/flavor/actuator.go +++ b/internal/controllers/flavor/actuator.go @@ -28,6 +28,7 @@ import ( orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" generic "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" osclients "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" ) @@ -36,16 +37,20 @@ import ( type ( osResourceT = flavors.Flavor - createResourceActuator = generic.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] - deleteResourceActuator = generic.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] - helperFactory = generic.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] + createResourceActuator = generic.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = generic.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + reconcileResourceActuator = generic.ReconcileResourceActuator[orcObjectPT, osResourceT] + resourceReconciler = generic.ResourceReconciler[orcObjectPT, osResourceT] + helperFactory = generic.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] ) type flavorClient interface { GetFlavor(context.Context, string) (*flavors.Flavor, error) ListFlavors(context.Context, flavors.ListOptsBuilder) iter.Seq2[*flavors.Flavor, error] CreateFlavor(context.Context, flavors.CreateOptsBuilder) (*flavors.Flavor, error) + CreateFlavorExtraSpecs(context.Context, string, flavors.CreateExtraSpecsOptsBuilder) (map[string]string, error) DeleteFlavor(context.Context, string) error + DeleteFlavorExtraSpec(context.Context, string, string) error } type flavorActuator struct { @@ -152,6 +157,7 @@ func (actuator flavorActuator) CreateResource(ctx context.Context, obj orcObject IsPublic: resource.IsPublic, Ephemeral: ptr.To(int(resource.Ephemeral)), Description: ptr.Deref(resource.Description, ""), + ID: resource.ID, } osResource, err := actuator.osClient.CreateFlavor(ctx, createOpts) @@ -170,6 +176,108 @@ func (actuator flavorActuator) DeleteResource(ctx context.Context, _ orcObjectPT return progress.WrapError(actuator.osClient.DeleteFlavor(ctx, flavor.ID)) } +func (actuator flavorActuator) reconcileExtraSpecs(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + return nil + } + + desiredExtraSpecs := extraSpecsToMap(resource.ExtraSpecs) + currentExtraSpecs := osResource.ExtraSpecs + + updates := extraSpecUpdates(desiredExtraSpecs, currentExtraSpecs) + deletes := extraSpecDeletes(desiredExtraSpecs, currentExtraSpecs) + + if len(updates) == 0 && len(deletes) == 0 { + log.V(logging.Debug).Info("No changes") + return nil + } + + if len(updates) > 0 { + _, err := actuator.osClient.CreateFlavorExtraSpecs( + ctx, + osResource.ID, + flavors.ExtraSpecsOpts(updates), + ) + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal( + orcv1alpha1.ConditionReasonInvalidConfiguration, + "invalid configuration updating resource extra specs: "+err.Error(), + err, + ) + } + return progress.WrapError(err) + } + } + + for _, d := range deletes { + if err := actuator.osClient.DeleteFlavorExtraSpec( + ctx, + osResource.ID, + d, + ); err != nil { + if orcerrors.IsNotFound(err) { + continue + } + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal( + orcv1alpha1.ConditionReasonInvalidConfiguration, + "invalid configuration deleting resource extra spec: "+err.Error(), + err, + ) + } + return progress.WrapError(err) + } + } + + return progress.NeedsRefresh() +} + +func extraSpecsToMap(extraSpecs []orcv1alpha1.FlavorExtraSpec) map[string]string { + specs := make(map[string]string) + + for _, spec := range extraSpecs { + specs[spec.Name] = spec.Value + } + + return specs +} + +func extraSpecUpdates(desired, current map[string]string) map[string]string { + updates := make(map[string]string) + + for k, v := range desired { + cur, exists := current[k] + if !exists || cur != v { + updates[k] = v + } + } + + return updates +} + +func extraSpecDeletes(desired, current map[string]string) []string { + var deletes []string + + for k := range current { + if _, found := desired[k]; !found { + deletes = append(deletes, k) + } + } + + return deletes +} + +var _ reconcileResourceActuator = flavorActuator{} + +func (actuator flavorActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller generic.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.reconcileExtraSpecs, + }, nil +} + type flavorHelperFactory struct{} var _ helperFactory = flavorHelperFactory{} diff --git a/internal/controllers/flavor/actuator_test.go b/internal/controllers/flavor/actuator_test.go index 40be7dd4e..6f7b171cc 100644 --- a/internal/controllers/flavor/actuator_test.go +++ b/internal/controllers/flavor/actuator_test.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "iter" + "reflect" + "sort" "testing" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors" @@ -44,10 +46,18 @@ func (l mockFlavorClient) CreateFlavor(_ context.Context, _ flavors.CreateOptsBu return nil, errNotImplemented } +func (l mockFlavorClient) CreateFlavorExtraSpecs(_ context.Context, _ string, _ flavors.CreateExtraSpecsOptsBuilder) (map[string]string, error) { + return nil, errNotImplemented +} + func (l mockFlavorClient) DeleteFlavor(_ context.Context, _ string) error { return errNotImplemented } +func (l mockFlavorClient) DeleteFlavorExtraSpec(_ context.Context, _, _ string) error { + return errNotImplemented +} + type flavorResult struct { flavor *flavors.Flavor err error @@ -377,3 +387,184 @@ func TestGetFlavorBySpec(t *testing.T) { }) } } + +func TestExtraSpecUpdates(t *testing.T) { + tests := []struct { + name string + desired map[string]string + current map[string]string + expected map[string]string + }{ + { + name: "No changes", + desired: map[string]string{"a": "1"}, + current: map[string]string{"a": "1"}, + expected: map[string]string{}, + }, + { + name: "Create new key", + desired: map[string]string{"a": "1"}, + current: map[string]string{}, + expected: map[string]string{"a": "1"}, + }, + { + name: "Update value", + desired: map[string]string{"a": "2"}, + current: map[string]string{"a": "1"}, + expected: map[string]string{"a": "2"}, + }, + { + name: "Multiple keys mixed", + desired: map[string]string{"a": "2", "b": "1"}, + current: map[string]string{"a": "1", "c": "9"}, + expected: map[string]string{"a": "2", "b": "1"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := extraSpecUpdates(tt.desired, tt.current) + + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("extraSpecUpdates() = %#v, want %#v", got, tt.expected) + } + }) + } +} + +func TestExtraSpecDeletes(t *testing.T) { + tests := []struct { + name string + desired map[string]string + current map[string]string + expected []string + }{ + { + name: "No deletes", + desired: map[string]string{"a": "1"}, + current: map[string]string{"a": "1"}, + expected: nil, + }, + { + name: "Delete missing key", + desired: map[string]string{}, + current: map[string]string{"a": "1"}, + expected: []string{"a"}, + }, + { + name: "Partial delete", + desired: map[string]string{"a": "1"}, + current: map[string]string{"a": "1", "b": "2"}, + expected: []string{"b"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := extraSpecDeletes(tt.desired, tt.current) + + sort.Strings(got) + sort.Strings(tt.expected) + + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("extraSpecDeletes() = %#v, want %#v", got, tt.expected) + } + }) + } +} + +type updateMockFlavorClient struct { + mockFlavorClient + errCreate error + errDelete error +} + +func (m updateMockFlavorClient) CreateFlavorExtraSpecs(_ context.Context, _ string, _ flavors.CreateExtraSpecsOptsBuilder) (map[string]string, error) { + return nil, m.errCreate +} + +func (m updateMockFlavorClient) DeleteFlavorExtraSpec(_ context.Context, _, _ string) error { + return m.errDelete +} + +func TestReconcileExtraSpecs(t *testing.T) { + tests := []struct { + name string + specSpecs []orcv1alpha1.FlavorExtraSpec + currSpecs map[string]string + client updateMockFlavorClient + expectError error + expectRefresh bool + }{ + { + name: "No changes needed", + specSpecs: []orcv1alpha1.FlavorExtraSpec{{Name: "hw:numa_nodes", Value: "2"}}, + currSpecs: map[string]string{"hw:numa_nodes": "2"}, + client: updateMockFlavorClient{}, + expectError: nil, + expectRefresh: false, + }, + { + name: "Successful modification", + specSpecs: []orcv1alpha1.FlavorExtraSpec{{Name: "hw:numa_nodes", Value: "4"}}, + currSpecs: map[string]string{"hw:numa_nodes": "2"}, + client: updateMockFlavorClient{}, + expectError: nil, + expectRefresh: true, + }, + { + name: "Update fails early", + specSpecs: []orcv1alpha1.FlavorExtraSpec{{Name: "new_key", Value: "true"}}, + currSpecs: map[string]string{}, + client: updateMockFlavorClient{errCreate: errTest}, + expectError: errTest, + expectRefresh: false, + }, + { + name: "Update succeeds but delete fails", + specSpecs: []orcv1alpha1.FlavorExtraSpec{}, + currSpecs: map[string]string{"old_key": "remove-me"}, + client: updateMockFlavorClient{errDelete: errTest}, + expectError: errTest, + expectRefresh: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + + actuator := flavorActuator{tt.client} + + obj := &orcv1alpha1.Flavor{ + Spec: orcv1alpha1.FlavorSpec{ + Resource: &orcv1alpha1.FlavorResourceSpec{ + ExtraSpecs: tt.specSpecs, + }, + }, + } + + osResource := &flavors.Flavor{ + ID: "test-flavor-id", + ExtraSpecs: tt.currSpecs, + } + + status := actuator.reconcileExtraSpecs(ctx, obj, osResource) + + if tt.expectError != nil { + if status == nil || status.GetError() == nil { + t.Fatalf("Expected error %v, got none", tt.expectError) + } + if !errors.Is(status.GetError(), tt.expectError) { + t.Errorf("Expected error %v, got %v", tt.expectError, status.GetError()) + } + } else { + if status != nil && status.GetError() != nil { + t.Errorf("Unexpected error: %v", status.GetError()) + } + gotRefresh := (status != nil) + if gotRefresh != tt.expectRefresh { + t.Errorf("Refresh expectation mismatch: expected %v, got %v", tt.expectRefresh, gotRefresh) + } + } + }) + } +} diff --git a/internal/controllers/flavor/controller.go b/internal/controllers/flavor/controller.go index 3b3cd459d..0f76371dd 100644 --- a/internal/controllers/flavor/controller.go +++ b/internal/controllers/flavor/controller.go @@ -19,6 +19,7 @@ package flavor import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -37,19 +38,24 @@ const controllerName = "flavor" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=flavors/status,verbs=get;update;patch type flavorReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return flavorReconcilerConstructor{scopeFactory: scopeFactory} + return &flavorReconcilerConstructor{scopeFactory: scopeFactory} } func (flavorReconcilerConstructor) GetName() string { return controllerName } +func (c *flavorReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c flavorReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *flavorReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) builder := ctrl.NewControllerManagedBy(mgr). @@ -63,6 +69,6 @@ func (c flavorReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, flavorHelperFactory{}, flavorStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, flavorHelperFactory{}, flavorStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/flavor/status.go b/internal/controllers/flavor/status.go index 697df64ef..3c2b4d76a 100644 --- a/internal/controllers/flavor/status.go +++ b/internal/controllers/flavor/status.go @@ -65,6 +65,11 @@ func (flavorStatusWriter) ApplyResourceStatus(_ logr.Logger, osResource *flavors if osResource.Ephemeral > 0 { resourceStatus.WithEphemeral(int32(osResource.Ephemeral)) } + for k, v := range osResource.ExtraSpecs { + resourceStatus.WithExtraSpecs(orcapplyconfigv1alpha1.FlavorExtraSpecStatus(). + WithName(k). + WithValue(v)) + } if osResource.Description != "" { resourceStatus.WithDescription(osResource.Description) } diff --git a/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml b/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml index 2074a3ece..94a024ae5 100644 --- a/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml +++ b/internal/controllers/flavor/tests/flavor-create-full/00-assert.yaml @@ -4,6 +4,7 @@ kind: Flavor metadata: name: flavor-create-full status: + id: testId-123 resource: name: flavor-create-full-override description: Flavor from "create full" test @@ -13,3 +14,6 @@ status: swap: 2 isPublic: false ephemeral: 1 + extraSpecs: + - name: spec + value: specValue diff --git a/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml b/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml index f705c1af5..de6789f29 100644 --- a/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml +++ b/internal/controllers/flavor/tests/flavor-create-full/00-create-resource.yaml @@ -17,3 +17,7 @@ spec: swap: 2 isPublic: false ephemeral: 1 + id: testId-123 + extraSpecs: + - name: spec + value: specValue diff --git a/internal/controllers/flavor/tests/flavor-update/00-assert.yaml b/internal/controllers/flavor/tests/flavor-update/00-assert.yaml new file mode 100644 index 000000000..ffe085e81 --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/00-assert.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Flavor + name: flavor-update + ref: flavor +assertAll: + - celExpr: "!has(flavor.status.resource.extraSpecs)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Flavor +metadata: + name: flavor-update +status: + resource: + disk: 0 + isPublic: true + name: flavor-update + ram: 1 + vcpus: 2 + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/flavor/tests/flavor-update/00-minimal-resource.yaml b/internal/controllers/flavor/tests/flavor-update/00-minimal-resource.yaml new file mode 100644 index 000000000..827048769 --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/00-minimal-resource.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Flavor +metadata: + name: flavor-update +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + ram: 1 + vcpus: 2 + disk: 0 diff --git a/internal/controllers/flavor/tests/flavor-update/00-prerequisites.yaml b/internal/controllers/flavor/tests/flavor-update/00-prerequisites.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/00-prerequisites.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/flavor/tests/flavor-update/01-assert.yaml b/internal/controllers/flavor/tests/flavor-update/01-assert.yaml new file mode 100644 index 000000000..b98226b93 --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/01-assert.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Flavor +metadata: + name: flavor-update +status: + resource: + disk: 0 + extraSpecs: + - name: spec + value: specValue + isPublic: true + name: flavor-update + ram: 1 + vcpus: 2 + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/flavor/tests/flavor-update/01-updated-resource.yaml b/internal/controllers/flavor/tests/flavor-update/01-updated-resource.yaml new file mode 100644 index 000000000..9276df64b --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/01-updated-resource.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Flavor +metadata: + name: flavor-update +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + extraSpecs: + - name: spec + value: specValue diff --git a/internal/controllers/flavor/tests/flavor-update/02-assert.yaml b/internal/controllers/flavor/tests/flavor-update/02-assert.yaml new file mode 100644 index 000000000..ffe085e81 --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/02-assert.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Flavor + name: flavor-update + ref: flavor +assertAll: + - celExpr: "!has(flavor.status.resource.extraSpecs)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Flavor +metadata: + name: flavor-update +status: + resource: + disk: 0 + isPublic: true + name: flavor-update + ram: 1 + vcpus: 2 + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/flavor/tests/flavor-update/02-reverted-resource.yaml b/internal/controllers/flavor/tests/flavor-update/02-reverted-resource.yaml new file mode 100644 index 000000000..2c6c253ff --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/02-reverted-resource.yaml @@ -0,0 +1,7 @@ +# NOTE: kuttl only does patch updates, which means we can't delete a field. +# We have to use a kubectl apply command instead. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl replace -f 00-minimal-resource.yaml + namespaced: true diff --git a/internal/controllers/flavor/tests/flavor-update/README.md b/internal/controllers/flavor/tests/flavor-update/README.md new file mode 100644 index 000000000..93708de17 --- /dev/null +++ b/internal/controllers/flavor/tests/flavor-update/README.md @@ -0,0 +1,17 @@ +# Update Flavor + +## Step 00 + +Create a Flavor using only mandatory fields. + +## Step 01 + +Update all mutable fields. + +## Step 02 + +Revert the resource to its original value and verify the resulting object is similar to when if was first created. + +## Reference + +https://k-orc.cloud/development/writing-tests/#update diff --git a/internal/controllers/flavor/zz_generated.adapter.go b/internal/controllers/flavor/zz_generated.adapter.go index c82b74162..49af59c95 100644 --- a/internal/controllers/flavor/zz_generated.adapter.go +++ b/internal/controllers/flavor/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package flavor import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/flavor/zz_generated.controller.go b/internal/controllers/flavor/zz_generated.controller.go index 38cf8b85c..675989cc0 100644 --- a/internal/controllers/flavor/zz_generated.controller.go +++ b/internal/controllers/flavor/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/floatingip/actuator.go b/internal/controllers/floatingip/actuator.go index 05a15a061..e83148490 100644 --- a/internal/controllers/floatingip/actuator.go +++ b/internal/controllers/floatingip/actuator.go @@ -18,7 +18,6 @@ package floatingip import ( "context" - "fmt" "iter" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/floatingips" @@ -27,10 +26,10 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" osclients "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -47,15 +46,11 @@ type ( ) type floatingipActuator struct { - osClient osclients.NetworkClient -} - -type floatingipCreateActuator struct { - floatingipActuator + osClient osclients.NetworkClient k8sClient client.Client } -var _ createResourceActuator = floatingipCreateActuator{} +var _ createResourceActuator = floatingipActuator{} var _ deleteResourceActuator = floatingipActuator{} func (floatingipActuator) GetResourceID(osResource *osResourceT) string { @@ -71,80 +66,88 @@ func (actuator floatingipActuator) GetOSResourceByID(ctx context.Context, id str } func (actuator floatingipActuator) ListOSResourcesForAdoption(ctx context.Context, obj *orcv1alpha1.FloatingIP) (floatingipIterator, bool) { - if obj.Spec.Resource == nil { + resource := obj.Spec.Resource + if resource == nil { return nil, false } // we only support adoption of floatingips by IP as they don't have name - if obj.Spec.Resource.FloatingIP == nil { + if resource.FloatingIP == nil { return nil, false } + // Resolve the floating network ID from either FloatingNetworkRef or + // FloatingSubnetRef. Exactly one of these must be set per API + // validation. Without the network ID, adoption could match a floating + // IP on the wrong network. + var floatingNetworkID string + if resource.FloatingNetworkRef != nil { + network, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.FloatingNetworkRef, "Network", + func(dep *orcv1alpha1.Network) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + floatingNetworkID = ptr.Deref(network.Status.ID, "") + } else if resource.FloatingSubnetRef != nil { + subnet, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.FloatingSubnetRef, "Subnet", + func(dep *orcv1alpha1.Subnet) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil && dep.Status.Resource != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + floatingNetworkID = subnet.Status.Resource.NetworkID + } + + // Resolve the project ID from ProjectRef if set. + var projectID string + if resource.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + listOpts := floatingips.ListOpts{ - FloatingIP: string(ptr.Deref(obj.Spec.Resource.FloatingIP, "")), - Tags: tags.Join(obj.Spec.Resource.Tags), + FloatingIP: string(ptr.Deref(resource.FloatingIP, "")), + FloatingNetworkID: floatingNetworkID, + ProjectID: projectID, + Tags: tags.Join(resource.Tags), } return actuator.osClient.ListFloatingIP(ctx, listOpts), true } -func (actuator floatingipCreateActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { +func (actuator floatingipActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { var reconcileStatus progress.ReconcileStatus - network := &orcv1alpha1.Network{} - if filter.FloatingNetworkRef != nil { - networkKey := client.ObjectKey{Name: string(ptr.Deref(filter.FloatingNetworkRef, "")), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, networkKey, network); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Network", networkKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching network %s: %w", networkKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(network) || network.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Network", networkKey.Name, progress.WaitingOnReady)) - } - } - } + network, rs := dependency.FetchDependency[*orcv1alpha1.Network]( + ctx, actuator.k8sClient, obj.Namespace, filter.FloatingNetworkRef, "Network", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) - port := &orcv1alpha1.Port{} - if filter.PortRef != nil { - portKey := client.ObjectKey{Name: string(ptr.Deref(filter.PortRef, "")), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, portKey, port); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Port", portKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching port %s: %w", portKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(port) || port.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Port", portKey.Name, progress.WaitingOnReady)) - } - } - } + port, rs := dependency.FetchDependency[*orcv1alpha1.Port]( + ctx, actuator.k8sClient, obj.Namespace, filter.PortRef, "Port", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) - project := &orcv1alpha1.Project{} - if filter.ProjectRef != nil { - projectKey := client.ObjectKey{Name: string(*filter.ProjectRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, projectKey, project); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching project %s: %w", projectKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(project) || project.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnReady)) - } - } - } + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -166,7 +169,7 @@ func (actuator floatingipCreateActuator) ListOSResourcesForImport(ctx context.Co return actuator.osClient.ListFloatingIP(ctx, listOpts), nil } -func (actuator floatingipCreateActuator) CreateResource(ctx context.Context, obj *orcv1alpha1.FloatingIP) (*osResourceT, progress.ReconcileStatus) { +func (actuator floatingipActuator) CreateResource(ctx context.Context, obj *orcv1alpha1.FloatingIP) (*osResourceT, progress.ReconcileStatus) { resource := obj.Spec.Resource if resource == nil { // Should have been caught by API validation @@ -179,9 +182,7 @@ func (actuator floatingipCreateActuator) CreateResource(ctx context.Context, obj if resource.FloatingNetworkRef != nil { // Fetch dependencies and ensure they have our finalizer network, networkDepRS := networkDep.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Network) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(networkDepRS) if network != nil { @@ -194,9 +195,7 @@ func (actuator floatingipCreateActuator) CreateResource(ctx context.Context, obj if resource.FloatingSubnetRef != nil { // Fetch dependencies and ensure they have our finalizer subnet, subnetDepRS := subnetDep.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Subnet) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(subnetDepRS) if subnet != nil { @@ -209,9 +208,7 @@ func (actuator floatingipCreateActuator) CreateResource(ctx context.Context, obj if resource.PortRef != nil { // Fetch dependencies and ensure they have our finalizer port, portDepRS := portDep.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Port) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(portDepRS) if port != nil { @@ -222,9 +219,7 @@ func (actuator floatingipCreateActuator) CreateResource(ctx context.Context, obj var projectID string if resource.ProjectRef != nil { project, projectDepRS := projectDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Project) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) if project != nil { @@ -248,12 +243,10 @@ func (actuator floatingipCreateActuator) CreateResource(ctx context.Context, obj osResource, err := actuator.osClient.CreateFloatingIP(ctx, &createOpts) - // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } return nil, progress.WrapError(err) } return osResource, nil @@ -289,10 +282,10 @@ func (actuator floatingipActuator) updateResource(ctx context.Context, obj orcOb _, err = actuator.osClient.UpdateFloatingIP(ctx, osResource.ID, updateOpts) - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } @@ -338,7 +331,7 @@ func (floatingipHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { } func (floatingipHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { - return newCreateActuator(ctx, orcObject, controller) + return newActuator(ctx, orcObject, controller) } func (floatingipHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { @@ -364,18 +357,7 @@ func newActuator(ctx context.Context, orcObject *orcv1alpha1.FloatingIP, control } return floatingipActuator{ - osClient: osClient, - }, nil -} - -func newCreateActuator(ctx context.Context, orcObject *orcv1alpha1.FloatingIP, controller interfaces.ResourceController) (floatingipCreateActuator, progress.ReconcileStatus) { - floatingipActuator, reconcileStatus := newActuator(ctx, orcObject, controller) - if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { - return floatingipCreateActuator{}, reconcileStatus - } - - return floatingipCreateActuator{ - floatingipActuator: floatingipActuator, - k8sClient: controller.GetK8sClient(), + osClient: osClient, + k8sClient: controller.GetK8sClient(), }, nil } diff --git a/internal/controllers/floatingip/controller.go b/internal/controllers/floatingip/controller.go index 6cf68e27b..a573ec340 100644 --- a/internal/controllers/floatingip/controller.go +++ b/internal/controllers/floatingip/controller.go @@ -19,6 +19,7 @@ package floatingip import ( "context" "errors" + "time" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" @@ -39,17 +40,22 @@ import ( // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=floatingips/status,verbs=get;update;patch type floatingipReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return floatingipReconcilerConstructor{scopeFactory: scopeFactory} + return &floatingipReconcilerConstructor{scopeFactory: scopeFactory} } func (floatingipReconcilerConstructor) GetName() string { return controllerName } +func (c *floatingipReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + const controllerName = "floatingip" var ( @@ -136,7 +142,7 @@ var ( ) // SetupWithManager sets up the controller with the Manager. -func (c floatingipReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *floatingipReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := mgr.GetLogger().WithValues("controller", controllerName) k8sClient := mgr.GetClient() @@ -217,6 +223,6 @@ func (c floatingipReconcilerConstructor) SetupWithManager(ctx context.Context, m return err } - r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, floatingipHelperFactory{}, floatingipStatusWriter{}) + r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, floatingipHelperFactory{}, floatingipStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/floatingip/suite_test.go b/internal/controllers/floatingip/suite_test.go index f1a7eb8fa..2494c4c0e 100644 --- a/internal/controllers/floatingip/suite_test.go +++ b/internal/controllers/floatingip/suite_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + utilrand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -82,7 +83,7 @@ var _ = Describe("EnvTest sanity check", func() { It("should be able to create a namespace", func() { ctx := context.TODO() namespace := &corev1.Namespace{} - namespace.SetGenerateName("test-") + namespace.SetName("test-" + utilrand.String(10)) // Create the namespace Expect(k8sClient.Create(ctx, namespace)).To(Succeed(), "create namespace") diff --git a/internal/controllers/floatingip/tests/floatingip-create-full/00-create-resource.yaml b/internal/controllers/floatingip/tests/floatingip-create-full/00-create-resource.yaml index a8cc7ff44..d81053c9a 100644 --- a/internal/controllers/floatingip/tests/floatingip-create-full/00-create-resource.yaml +++ b/internal/controllers/floatingip/tests/floatingip-create-full/00-create-resource.yaml @@ -35,6 +35,9 @@ spec: networkRef: floatingip-create-full-external ipVersion: 4 cidr: 192.168.155.0/24 + allocationPools: + - start: 192.168.155.100 + end: 192.168.155.200 --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Router diff --git a/internal/controllers/floatingip/zz_generated.adapter.go b/internal/controllers/floatingip/zz_generated.adapter.go index 2c4796f71..018137366 100644 --- a/internal/controllers/floatingip/zz_generated.adapter.go +++ b/internal/controllers/floatingip/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package floatingip import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/floatingip/zz_generated.controller.go b/internal/controllers/floatingip/zz_generated.controller.go index 223181f4c..9d3324464 100644 --- a/internal/controllers/floatingip/zz_generated.controller.go +++ b/internal/controllers/floatingip/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/generic/interfaces/adapter.go b/internal/controllers/generic/interfaces/adapter.go index 319e19c10..932d9ca3f 100644 --- a/internal/controllers/generic/interfaces/adapter.go +++ b/internal/controllers/generic/interfaces/adapter.go @@ -33,6 +33,8 @@ type APIObjectAdapter[orcObjectPT any, resourceSpecT any, filterT any] interface GetManagementPolicy() orcv1alpha1.ManagementPolicy GetManagedOptions() *orcv1alpha1.ManagedOptions + GetResyncPeriod() *metav1.Duration + GetLastSyncTime() *metav1.Time GetStatusID() *string GetResourceSpec() *resourceSpecT diff --git a/internal/controllers/generic/interfaces/controller.go b/internal/controllers/generic/interfaces/controller.go index 87f81ccef..26f413ed8 100644 --- a/internal/controllers/generic/interfaces/controller.go +++ b/internal/controllers/generic/interfaces/controller.go @@ -18,6 +18,7 @@ package interfaces import ( "context" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -29,6 +30,7 @@ import ( type Controller interface { SetupWithManager(context.Context, ctrl.Manager, controller.Options) error GetName() string + SetDefaultResyncPeriod(time.Duration) } type ResourceController interface { diff --git a/internal/controllers/generic/interfaces/status.go b/internal/controllers/generic/interfaces/status.go index b577a364f..15cdf3fd4 100644 --- a/internal/controllers/generic/interfaces/status.go +++ b/internal/controllers/generic/interfaces/status.go @@ -35,9 +35,25 @@ type ORCApplyConfig[objectApplyPT any, statusApplyPT ORCStatusApplyConfig[status } // ORCStatusApplyConfig is an interface implemented by the status of any apply -// configuration for an ORC API object. It has Conditions and an ID field. +// configuration for an ORC API object. type ORCStatusApplyConfig[statusApplyPT any] interface { WithConditions(...*applyconfigv1.ConditionApplyConfiguration) statusApplyPT +} + +// ORCStatusApplyConfigWithLastSyncTime extends ORCStatusApplyConfig with a +// LastSyncTime field. +type ORCStatusApplyConfigWithLastSyncTime[statusApplyPT any] interface { + ORCStatusApplyConfig[statusApplyPT] + WithLastSyncTime(metav1.Time) statusApplyPT +} + +// ORCStatusApplyConfigWithID extends ORCStatusApplyConfigWithLastSyncTime with +// an ID field. +// This is required by resources that have an OpenStack-assigned ID stored in +// status.id. Resources without an ID (e.g. relationship resources like +// RoleAssignment) use only ORCStatusApplyConfig. +type ORCStatusApplyConfigWithID[statusApplyPT any] interface { + ORCStatusApplyConfigWithLastSyncTime[statusApplyPT] WithID(id string) statusApplyPT } diff --git a/internal/controllers/generic/progress/reconcile_status.go b/internal/controllers/generic/progress/reconcile_status.go index 9b9b61c99..8277d6fea 100644 --- a/internal/controllers/generic/progress/reconcile_status.go +++ b/internal/controllers/generic/progress/reconcile_status.go @@ -42,6 +42,8 @@ type reconcileStatus struct { requeue time.Duration err error + + externallyDeleted bool } // NewReconcileStatus returns an empty ReconcileStatus @@ -177,9 +179,36 @@ func (r ReconcileStatus) WithReconcileStatus(o ReconcileStatus) ReconcileStatus return o } - return r.WithProgressMessage(o.GetProgressMessages()...). + r = r.WithProgressMessage(o.GetProgressMessages()...). WithRequeue(o.GetRequeue()). WithError(o.GetError()) + r.externallyDeleted = r.IsExternallyDeleted() || o.IsExternallyDeleted() + return r +} + +// ExternallyDeleted returns a ReconcileStatus indicating that the OpenStack +// resource referenced by status.id has been deleted outside of ORC. The caller +// is expected to clear status.id and add an appropriate progress message. +func (r ReconcileStatus) ExternallyDeleted() ReconcileStatus { + if r == nil { + r = &reconcileStatus{} + } + r.externallyDeleted = true + return r +} + +// ExternallyDeleted is a convenience method which returns a new ReconcileStatus with ExternallyDeleted. +func ExternallyDeleted() ReconcileStatus { + return NewReconcileStatus().ExternallyDeleted() +} + +// IsExternallyDeleted returns true if the ReconcileStatus indicates that the +// OpenStack resource was deleted externally. +func (r ReconcileStatus) IsExternallyDeleted() bool { + if r == nil { + return false + } + return r.externallyDeleted } // WaitingOnEvent represents the type of event we are waiting on diff --git a/internal/controllers/generic/reconciler/controller.go b/internal/controllers/generic/reconciler/controller.go index 7571519cd..e1c1a9ed1 100644 --- a/internal/controllers/generic/reconciler/controller.go +++ b/internal/controllers/generic/reconciler/controller.go @@ -19,6 +19,7 @@ package reconciler import ( "context" "fmt" + "time" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -29,6 +30,7 @@ import ( orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/resync" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/status" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/scope" @@ -51,20 +53,22 @@ func NewController[ objectApplyPT interfaces.ORCApplyConfig[objectApplyPT, statusApplyPT], statusApplyPT interface { *statusApplyT - interfaces.ORCStatusApplyConfig[statusApplyPT] + interfaces.ORCStatusApplyConfigWithID[statusApplyPT] }, statusApplyT any, osResourceT any, ]( name string, k8sClient client.Client, scopeFactory scope.Factory, helperFactory interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT], statusWriter interfaces.ResourceStatusWriter[orcObjectPT, *osResourceT, objectApplyPT, statusApplyPT], + defaultResyncPeriod time.Duration, ) Controller[orcObjectPT, orcObjectT, resourceSpecT, filterT, objectApplyPT, statusApplyPT, statusApplyT, osResourceT] { return Controller[orcObjectPT, orcObjectT, resourceSpecT, filterT, objectApplyPT, statusApplyPT, statusApplyT, osResourceT]{ - name: name, - client: k8sClient, - scopeFactory: scopeFactory, - helperFactory: helperFactory, - statusWriter: statusWriter, + name: name, + client: k8sClient, + scopeFactory: scopeFactory, + helperFactory: helperFactory, + statusWriter: statusWriter, + defaultResyncPeriod: defaultResyncPeriod, } } @@ -80,7 +84,7 @@ type Controller[ objectApplyPT interfaces.ORCApplyConfig[objectApplyPT, statusApplyPT], statusApplyPT interface { *statusApplyT - interfaces.ORCStatusApplyConfig[statusApplyPT] + interfaces.ORCStatusApplyConfigWithID[statusApplyPT] }, statusApplyT any, osResourceT any, @@ -91,6 +95,13 @@ type Controller[ helperFactory interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] statusWriter interfaces.ResourceStatusWriter[orcObjectPT, *osResourceT, objectApplyPT, statusApplyPT] + + // defaultResyncPeriod is the operator-level default resync period passed + // from the manager options. It is used as the fallback in + // resync.DetermineResyncPeriod when a resource does not specify its own + // spec.resyncPeriod. A value of 0 means periodic resync is disabled by + // default. + defaultResyncPeriod time.Duration } func (c *Controller[_, _, _, _, _, _, _, _]) GetName() string { @@ -131,7 +142,7 @@ func (c *Controller[ return c.reconcileNormal(ctx, adapter).Return(log) } -// shouldReconcile filters events when the object status is up to date, and its +// ShouldReconcile filters events when the object status is up to date, and its // status indicates that no further reconciliation is required. // // Specifically it looks at the Progressing condition. It has the following behaviour: @@ -140,10 +151,22 @@ func (c *Controller[ // - Progressing condition is present and False, but observedGeneration is old -> reconcile // - Progressing condition is false and observedGeneration is up to date -> do not reconcile // -// If shouldReconcile is preventing an object from being reconciled which should +// If resyncPeriod > 0, periodic resync is also considered: +// - If lastSyncTime is nil (never synced), reconcile immediately. +// - If time.Since(lastSyncTime) >= resyncPeriod, a resync is due: reconcile. +// - If time.Since(lastSyncTime) < resyncPeriod, the next resync is not yet due: +// do not reconcile (unless condition-based logic above requires it). +// +// When resyncPeriod <= 0 (disabled), resync logic is not applied and the +// existing condition-based behaviour is unchanged. +// +// The resync check uses the persisted lastSyncTime so that controller restarts +// respect the time already elapsed, preventing a thundering herd. +// +// If ShouldReconcile is preventing an object from being reconciled which should // be reconciled, consider if that object's actuator is correctly returning a // ProgressStatus indicating that the reconciliation should continue. -func shouldReconcile(obj orcv1alpha1.ObjectWithConditions) bool { +func ShouldReconcile(obj orcv1alpha1.ObjectWithConditions, lastSyncTime *metav1.Time, resyncPeriod time.Duration) bool { progressing := meta.FindStatusCondition(obj.GetConditions(), orcv1alpha1.ConditionProgressing) if progressing == nil { return true @@ -153,7 +176,22 @@ func shouldReconcile(obj orcv1alpha1.ObjectWithConditions) bool { return true } - return progressing.ObservedGeneration != obj.GetGeneration() + if progressing.ObservedGeneration != obj.GetGeneration() { + return true + } + + // Condition-based check says no reconcile is needed. Now check if a + // periodic resync is due. + if resyncPeriod > 0 { + // Never synced: reconcile immediately. + if lastSyncTime == nil { + return true + } + // Resync is due when the elapsed time has reached the period. + return time.Since(lastSyncTime.Time) >= resyncPeriod + } + + return false } func (c *Controller[ @@ -168,8 +206,12 @@ func (c *Controller[ // We do this here rather than in a predicate because predicates only cover // a single watch. Doing it here means we cover all sources of // reconciliation, including our dependencies. - if !shouldReconcile(objAdapter.GetObject()) { + effectiveResyncPeriod := resync.DetermineResyncPeriod(objAdapter.GetResyncPeriod(), c.defaultResyncPeriod) + if !ShouldReconcile(objAdapter.GetObject(), objAdapter.GetLastSyncTime(), effectiveResyncPeriod) { log.V(logging.Verbose).Info("Status is up to date: not reconciling") + if remaining := resync.RemainingUntilNextSync(objAdapter.GetLastSyncTime(), effectiveResyncPeriod); remaining > 0 { + return reconcileStatus.WithRequeue(remaining) + } return reconcileStatus } @@ -192,6 +234,15 @@ func (c *Controller[ } osResource, getOSResourceRS := GetOrCreateOSResource(ctx, log, c, objAdapter, actuator) + if getOSResourceRS.IsExternallyDeleted() { + if objAdapter.GetStatusID() != nil { + log.V(logging.Info).Info("Clearing status.id after external deletion to enable recreation") + if err := status.ClearStatusID(ctx, c, objAdapter.GetObject()); err != nil { + return reconcileStatus.WithError(fmt.Errorf("clearing status ID after external deletion: %w", err)) + } + } + return reconcileStatus.WithProgressMessage("OpenStack resource was deleted externally; will recreate on next reconcile") + } if needsReschedule, err := getOSResourceRS.NeedsReschedule(); needsReschedule { if err == nil { log.V(logging.Verbose).Info("Waiting on events before creation") @@ -199,11 +250,6 @@ func (c *Controller[ return getOSResourceRS.WithReconcileStatus(reconcileStatus) } - if osResource == nil { - // Programming error: if we don't have a resource we should either have an error or be waiting on something - return reconcileStatus.WithError(fmt.Errorf("oResource is not set, but no wait events or error")) - } - if objAdapter.GetStatusID() == nil { resourceID := actuator.GetResourceID(osResource) if err := status.SetStatusID(ctx, c, objAdapter.GetObject(), resourceID, c.statusWriter); err != nil { @@ -229,6 +275,14 @@ func (c *Controller[ } } + // Schedule a resync requeue when the effective resync period is configured, + // there is no terminal error, and no other requeue is already pending. + // Positive-only jitter of [0%, +20%] is applied to spread load across + // resources sharing the same period. + if resync.ShouldScheduleResync(effectiveResyncPeriod, reconcileStatus) { + reconcileStatus = reconcileStatus.WithRequeue(resync.CalculateJitteredDuration(effectiveResyncPeriod)) + } + return reconcileStatus } diff --git a/internal/controllers/generic/reconciler/controller_test.go b/internal/controllers/generic/reconciler/controller_test.go new file mode 100644 index 000000000..d0bf80430 --- /dev/null +++ b/internal/controllers/generic/reconciler/controller_test.go @@ -0,0 +1,483 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package reconciler + +import ( + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/resync" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// makeObj creates a Flavor object with the given generation and conditions, +// satisfying orcv1alpha1.ObjectWithConditions. +func makeObj(generation int64, conditions []metav1.Condition) orcv1alpha1.ObjectWithConditions { + f := &orcv1alpha1.Flavor{} + f.Generation = generation + f.Status.Conditions = conditions + return f +} + +// makeProgressingCondition returns a Progressing condition with the given +// status and observedGeneration. +func makeProgressingCondition(status metav1.ConditionStatus, observedGeneration int64) metav1.Condition { //nolint:unparam + return metav1.Condition{ + Type: orcv1alpha1.ConditionProgressing, + Status: status, + ObservedGeneration: observedGeneration, + Reason: "Test", + } +} + +// agoPtr returns a *metav1.Time that is d in the past. +func agoPtr(d time.Duration) *metav1.Time { + t := metav1.NewTime(time.Now().Add(-d)) + return &t +} + +// nowPtr returns a *metav1.Time set to approximately now. +func nowPtr() *metav1.Time { + t := metav1.Now() + return &t +} + +func TestShouldReconcile_ConditionBased(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + generation int64 + conditions []metav1.Condition + lastSyncTime *metav1.Time + resyncPeriod time.Duration + want bool + }{ + { + name: "no conditions: should reconcile", + generation: 1, + conditions: nil, + want: true, + }, + { + name: "Progressing=True up-to-date: should reconcile", + generation: 1, + conditions: []metav1.Condition{ + makeProgressingCondition(metav1.ConditionTrue, 1), + }, + want: true, + }, + { + name: "Progressing=False up-to-date resync disabled: should not reconcile", + generation: 1, + conditions: []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }, + resyncPeriod: 0, + want: false, + }, + { + name: "Progressing=False stale generation: should reconcile", + generation: 2, + conditions: []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }, + want: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + obj := makeObj(tc.generation, tc.conditions) + got := ShouldReconcile(obj, tc.lastSyncTime, tc.resyncPeriod) + if got != tc.want { + t.Errorf("ShouldReconcile() = %v, want %v", got, tc.want) + } + }) + } +} + +func TestShouldReconcile_ResyncDisabled(t *testing.T) { + t.Parallel() + + // An up-to-date Progressing=False condition prevents reconciliation when + // resync is disabled (resyncPeriod <= 0). + obj := makeObj(1, []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }) + + tests := []struct { + name string + resyncPeriod time.Duration + lastSyncTime *metav1.Time + }{ + { + name: "resyncPeriod=0 nil lastSyncTime", + resyncPeriod: 0, + lastSyncTime: nil, + }, + { + name: "resyncPeriod=0 old lastSyncTime", + resyncPeriod: 0, + lastSyncTime: agoPtr(24 * time.Hour), + }, + { + name: "negative resyncPeriod", + resyncPeriod: -1 * time.Minute, + lastSyncTime: nil, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + got := ShouldReconcile(obj, tc.lastSyncTime, tc.resyncPeriod) + if got { + t.Errorf("ShouldReconcile() = true; want false when resync disabled (resyncPeriod=%v)", tc.resyncPeriod) + } + }) + } +} + +func TestShouldReconcile_ResyncEnabled_NilLastSyncTime(t *testing.T) { + t.Parallel() + + // When resyncPeriod > 0 and lastSyncTime is nil (never synced), reconcile + // immediately (persisted time is absent → treat as overdue). + obj := makeObj(1, []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }) + + got := ShouldReconcile(obj, nil, 10*time.Minute) + if !got { + t.Error("ShouldReconcile() = false; want true when lastSyncTime is nil and resyncPeriod > 0") + } +} + +func TestShouldReconcile_ResyncEnabled_PeriodElapsed(t *testing.T) { + t.Parallel() + + // When time.Since(lastSyncTime) >= resyncPeriod, a resync is due. + obj := makeObj(1, []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }) + + // Last synced 20 minutes ago, period is 10 minutes. + got := ShouldReconcile(obj, agoPtr(20*time.Minute), 10*time.Minute) + if !got { + t.Error("ShouldReconcile() = false; want true when time.Since(lastSyncTime) >= resyncPeriod") + } +} + +func TestShouldReconcile_ResyncEnabled_PeriodNotElapsed(t *testing.T) { + t.Parallel() + + // When time.Since(lastSyncTime) < resyncPeriod, no resync is due. + obj := makeObj(1, []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }) + + // Last synced 2 minutes ago, period is 10 minutes. + got := ShouldReconcile(obj, agoPtr(2*time.Minute), 10*time.Minute) + if got { + t.Error("ShouldReconcile() = true; want false when time.Since(lastSyncTime) < resyncPeriod") + } +} + +func TestShouldReconcile_ResyncEnabled_JustPastPeriod(t *testing.T) { + t.Parallel() + + // Boundary condition: just past the period should trigger resync (>= semantics). + obj := makeObj(1, []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }) + + resyncPeriod := 10 * time.Minute + // Add a small extra to ensure we're past the boundary even accounting for + // time elapsed during test execution. + lastSyncTime := agoPtr(resyncPeriod + 100*time.Millisecond) + + got := ShouldReconcile(obj, lastSyncTime, resyncPeriod) + if !got { + t.Error("ShouldReconcile() = false; want true when time.Since(lastSyncTime) is just past resyncPeriod") + } +} + +func TestShouldReconcile_ResyncEnabled_ProgressingTrue_IgnoresResyncNotElapsed(t *testing.T) { + t.Parallel() + + // Progressing=True always triggers reconciliation even if resync period has + // not elapsed yet (condition-based logic takes priority for positive cases). + obj := makeObj(1, []metav1.Condition{ + makeProgressingCondition(metav1.ConditionTrue, 1), + }) + + // lastSyncTime is very recent, so resync would say "false". + // But Progressing=True means we must reconcile anyway. + got := ShouldReconcile(obj, nowPtr(), time.Hour) + if !got { + t.Error("ShouldReconcile() = false; want true when Progressing=True regardless of resync period") + } +} + +func TestShouldReconcile_ResyncEnabled_ControllerRestart_PersistsLastSyncTime(t *testing.T) { + t.Parallel() + + // Thundering-herd prevention: after a controller restart, + // lastSyncTime is read from the persisted Kubernetes status. If the + // persisted time is recent, ShouldReconcile should return false so the + // controller does not immediately hammer OpenStack for all resources at once. + obj := makeObj(1, []metav1.Condition{ + makeProgressingCondition(metav1.ConditionFalse, 1), + }) + + resyncPeriod := 30 * time.Minute + // Simulated: last sync was 5 minutes ago (persisted from before restart). + lastSyncTime := agoPtr(5 * time.Minute) + + got := ShouldReconcile(obj, lastSyncTime, resyncPeriod) + if got { + t.Error("ShouldReconcile() = true; want false: controller should respect persisted lastSyncTime after restart") + } +} + +func TestShouldReconcile_ExistingBehaviorUnchanged_ResyncPeriodZero(t *testing.T) { + t.Parallel() + + // When resyncPeriod is 0 (disabled), ShouldReconcile behaves exactly as it + // did before the resync feature was added: only condition-based logic applies. + tests := []struct { + name string + generation int64 + conditions []metav1.Condition + want bool + }{ + { + name: "no conditions", + generation: 1, + want: true, + }, + { + name: "progressing true", + generation: 1, + conditions: []metav1.Condition{makeProgressingCondition(metav1.ConditionTrue, 1)}, + want: true, + }, + { + name: "progressing false up-to-date", + generation: 1, + conditions: []metav1.Condition{makeProgressingCondition(metav1.ConditionFalse, 1)}, + want: false, + }, + { + name: "progressing false stale", + generation: 2, + conditions: []metav1.Condition{makeProgressingCondition(metav1.ConditionFalse, 1)}, + want: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + obj := makeObj(tc.generation, tc.conditions) + // resyncPeriod=0 and nil lastSyncTime: pure condition-based behaviour. + got := ShouldReconcile(obj, nil, 0) + if got != tc.want { + t.Errorf("ShouldReconcile() = %v, want %v (existing behaviour should be unchanged)", got, tc.want) + } + }) + } +} + +// scheduleResyncRequeue simulates the resync scheduling logic added to the end +// of reconcileNormal: +// +// if resync.ShouldScheduleResync(effectiveResyncPeriod, reconcileStatus) { +// reconcileStatus = reconcileStatus.WithRequeue(resync.CalculateJitteredDuration(effectiveResyncPeriod)) +// } +// +// This helper allows the following tests to verify the combined behaviour of +// ShouldScheduleResync and CalculateJitteredDuration without requiring a full +// Kubernetes environment. +func scheduleResyncRequeue(reconcileStatus progress.ReconcileStatus, period time.Duration) progress.ReconcileStatus { + if resync.ShouldScheduleResync(period, reconcileStatus) { + reconcileStatus = reconcileStatus.WithRequeue(resync.CalculateJitteredDuration(period)) + } + return reconcileStatus +} + +// TestResyncRequeue_ScheduledWhenPeriodPositive verifies that a resync requeue +// is added to a clean ReconcileStatus when resyncPeriod > 0. +func TestResyncRequeue_ScheduledWhenPeriodPositive(t *testing.T) { + t.Parallel() + + const period = 10 * time.Minute + + // A clean (nil) ReconcileStatus represents a successful reconciliation with + // no errors and no pending requeue. + var rs progress.ReconcileStatus + rs = scheduleResyncRequeue(rs, period) + + requeue := rs.GetRequeue() + if requeue == 0 { + t.Fatal("expected a non-zero requeue duration after resync scheduling; got 0") + } + + // The requeue must be within the jitter range [period*1.0, period*1.2). + lo := time.Duration(float64(period) * 1.0) + hi := time.Duration(float64(period) * 1.2) + if requeue < lo || requeue > hi { + t.Errorf("resync requeue %v is outside jitter range [%v, %v]", requeue, lo, hi) + } +} + +// TestResyncRequeue_NotScheduledWhenPeriodZero verifies that no resync requeue +// is added when resyncPeriod is zero (disabled). +func TestResyncRequeue_NotScheduledWhenPeriodZero(t *testing.T) { + t.Parallel() + + var rs progress.ReconcileStatus + rs = scheduleResyncRequeue(rs, 0) + + if requeue := rs.GetRequeue(); requeue != 0 { + t.Errorf("expected no requeue when resyncPeriod=0; got %v", requeue) + } +} + +// TestResyncRequeue_NotScheduledWhenPeriodNegative verifies that no resync +// requeue is added when resyncPeriod is negative (effectively disabled). +func TestResyncRequeue_NotScheduledWhenPeriodNegative(t *testing.T) { + t.Parallel() + + var rs progress.ReconcileStatus + rs = scheduleResyncRequeue(rs, -1*time.Minute) + + if requeue := rs.GetRequeue(); requeue != 0 { + t.Errorf("expected no requeue when resyncPeriod<0; got %v", requeue) + } +} + +// TestResyncRequeue_NotScheduledWhenTerminalError verifies that no resync +// requeue is scheduled when the ReconcileStatus contains a terminal error. +// Terminal errors indicate the resource is in a non-retryable state; +// resyncing would be pointless and wasteful. +func TestResyncRequeue_NotScheduledWhenTerminalError(t *testing.T) { + t.Parallel() + + const period = 10 * time.Minute + + termErr := orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid config", nil) + rs := progress.WrapError(termErr) + rs = scheduleResyncRequeue(rs, period) + + if requeue := rs.GetRequeue(); requeue != 0 { + t.Errorf("expected no resync requeue on terminal error; got %v", requeue) + } +} + +// TestResyncRequeue_NotScheduledWhenRequeueAlreadyPending verifies that no +// additional resync requeue is scheduled when one is already set. +// This prevents redundant requeues when the reconciler is already waiting on +// an OpenStack event or dependency. +func TestResyncRequeue_NotScheduledWhenRequeueAlreadyPending(t *testing.T) { + t.Parallel() + + const period = 10 * time.Minute + const existingRequeue = 5 * time.Second + + // Simulate a reconcile status that already has a short requeue (e.g., waiting + // for an OpenStack resource to become ready). + rs := progress.NewReconcileStatus().WithRequeue(existingRequeue) + rs = scheduleResyncRequeue(rs, period) + + // The existing requeue must be preserved unchanged; no extra requeue added. + if requeue := rs.GetRequeue(); requeue != existingRequeue { + t.Errorf("expected existing requeue %v to be preserved; got %v", existingRequeue, requeue) + } +} + +// TestResyncRequeue_JitterIsApplied verifies that multiple scheduling calls +// with the same period produce different requeue durations (jitter is random), +// and all values are within the expected [+0%, +20%] range. +func TestResyncRequeue_JitterIsApplied(t *testing.T) { + t.Parallel() + + const samples = 200 + period := time.Hour + + lo := time.Duration(float64(period) * 1.0) + hi := time.Duration(float64(period) * 1.2) + + unique := make(map[time.Duration]struct{}, samples) + for i := range samples { + var rs progress.ReconcileStatus + rs = scheduleResyncRequeue(rs, period) + d := rs.GetRequeue() + if d < lo || d > hi { + t.Errorf("sample %d: requeue %v outside jitter range [%v, %v]", i, d, lo, hi) + } + unique[d] = struct{}{} + } + + // With 200 samples from a continuous distribution, we expect nearly all + // values to be distinct. Require at least 90% uniqueness. + minUnique := samples * 9 / 10 + if len(unique) < minUnique { + t.Errorf("jitter appears non-random: only %d unique values out of %d samples (want >= %d)", len(unique), samples, minUnique) + } +} + +// TestResyncRequeue_RequeueTimingRange verifies the requeue timing over many +// samples remains within the [+0%, +20%] jitter window, functioning as an +// integration check of the scheduling logic used in reconcileNormal. +func TestResyncRequeue_RequeueTimingRange(t *testing.T) { + t.Parallel() + + periods := []time.Duration{ + time.Minute, + 10 * time.Minute, + time.Hour, + 24 * time.Hour, + } + + for _, period := range periods { + t.Run(period.String(), func(t *testing.T) { + t.Parallel() + + lo := time.Duration(float64(period) * 1.0) + hi := time.Duration(float64(period) * 1.2) + + for i := range 50 { + var rs progress.ReconcileStatus + rs = scheduleResyncRequeue(rs, period) + d := rs.GetRequeue() + if d < lo || d > hi { + t.Errorf("sample %d: period=%v requeue=%v outside [%v, %v]", + i, period, d, lo, hi) + } + } + }) + } +} diff --git a/internal/controllers/generic/reconciler/resource_actions.go b/internal/controllers/generic/reconciler/resource_actions.go index 49f4598b1..62aabad7c 100644 --- a/internal/controllers/generic/reconciler/resource_actions.go +++ b/internal/controllers/generic/reconciler/resource_actions.go @@ -70,16 +70,26 @@ func GetOrCreateOSResource[ osResource, reconcileStatus := actuator.GetOSResourceByID(ctx, *resourceID) if needsReschedule, err := reconcileStatus.NeedsReschedule(); needsReschedule { if orcerrors.IsNotFound(err) { - // An OpenStack resource we previously referenced has been deleted unexpectedly. We can't recover from this. + // The OpenStack resource referenced by status.id no longer exists. + // For managed resources we trigger recreation by returning a typed + // signal: the caller will clear status.id and re-enter the creation + // path on the next reconcile. + // For unmanaged resources we cannot recreate them, so we return a + // terminal error. + if objAdapter.GetManagementPolicy() == orcv1alpha1.ManagementPolicyManaged { + log.V(logging.Info).Info("OpenStack resource was deleted externally; will signal caller to clear status ID and trigger recreation") + return nil, progress.ExternallyDeleted() + } return osResource, progress.WrapError( orcerrors.Terminal(orcv1alpha1.ConditionReasonUnrecoverableError, "resource has been deleted from OpenStack")) } else { return osResource, reconcileStatus } } - if osResource != nil { - log.V(logging.Verbose).Info("Got existing OpenStack resource", "ID", actuator.GetResourceID(osResource)) + if osResource == nil { + return nil, progress.WrapError(fmt.Errorf("GetOSResourceByID returned nil resource with no error for ID %q", *resourceID)) } + log.V(logging.Verbose).Info("Got existing OpenStack resource", "ID", actuator.GetResourceID(osResource)) return osResource, nil } diff --git a/internal/controllers/generic/reconciler/resource_actions_test.go b/internal/controllers/generic/reconciler/resource_actions_test.go new file mode 100644 index 000000000..5c83007e0 --- /dev/null +++ b/internal/controllers/generic/reconciler/resource_actions_test.go @@ -0,0 +1,119 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package reconciler contains unit tests for external deletion handling in +// GetOrCreateOSResource. +// +// These tests cover management policy behaviour when a resource's OpenStack +// counterpart is not found (404), verifying that: +// +// - Managed resources trigger recreation (IsExternallyDeleted) +// - Unmanaged resources return a terminal error +// - Managed, existing resources continue through the normal update flow +package reconciler + +import ( + "context" + "errors" + "testing" + + "github.com/go-logr/logr" + + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// -------------------------------------------------------------------------- +// External deletion tests — all use GetOrCreateOSResource directly. +// -------------------------------------------------------------------------- + +// TestGetOrCreateOSResource_ExternalDeletion_ManagedOrcCreated verifies that +// when a managed resource is externally deleted, +// GetOrCreateOSResource returns IsExternallyDeleted to signal the caller should +// clear status.ID and trigger recreation on the next reconcile. +func TestGetOrCreateOSResource_ExternalDeletion_ManagedOrcCreated(t *testing.T) { + t.Parallel() + + const resourceID = "orc-created-flavor-id" + + actuator := &noWriteActuator{t: t, readByIDErr: notFoundErr()} + adapter := managedFlavorWithStatusID(resourceID) + + got, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + if !rs.IsExternallyDeleted() { + t.Fatal("expected IsExternallyDeleted for externally-deleted managed resource") + } + if got != nil { + t.Errorf("expected nil osResource for recreation path, got %v", got) + } + if !actuator.getByIDCalled { + t.Error("GetOSResourceByID was not called: controller must attempt to fetch the resource") + } +} + +// TestGetOrCreateOSResource_ExternalDeletion_Unmanaged verifies that when an +// unmanaged resource is externally deleted (404), the controller returns a +// terminal error instead of calling CreateResource. +func TestGetOrCreateOSResource_ExternalDeletion_Unmanaged(t *testing.T) { + t.Parallel() + + const resourceID = "unmanaged-deleted-flavor-id" + + actuator := &noWriteActuator{t: t, readByIDErr: notFoundErr()} + adapter := unmanagedFlavorWithStatusID(resourceID) + + _, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + _, err := rs.NeedsReschedule() + if err == nil { + t.Fatal("expected a terminal error for externally-deleted unmanaged resource, got nil") + } + + var termErr *orcerrors.TerminalError + if !errors.As(err, &termErr) { + t.Errorf("expected a TerminalError for externally-deleted unmanaged resource, got %T: %v", err, err) + } + if !actuator.getByIDCalled { + t.Error("GetOSResourceByID was not called: controller must attempt to fetch the resource") + } +} + +// TestGetOrCreateOSResource_ExternalDeletion_ManagedResourceExists verifies +// the normal update flow: when a managed resource still exists in +// OpenStack, GetOrCreateOSResource returns the resource with a nil reconcile +// status so the caller proceeds with reconciliation (no recreation, no error). +func TestGetOrCreateOSResource_ExternalDeletion_ManagedResourceExists(t *testing.T) { + t.Parallel() + + const resourceID = "existing-managed-flavor-id" + osResource := &fakeOSResource{ID: resourceID} + + actuator := &noWriteActuator{t: t, readByIDResult: osResource} + adapter := managedFlavorWithStatusID(resourceID) + + got, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + needsReschedule, err := rs.NeedsReschedule() + if needsReschedule { + t.Fatalf("expected no rescheduling for existing resource, got needsReschedule=%v err=%v", needsReschedule, err) + } + if got == nil || got.ID != resourceID { + t.Errorf("expected osResource with ID=%q, got %v", resourceID, got) + } + if !actuator.getByIDCalled { + t.Error("GetOSResourceByID was not called") + } +} diff --git a/internal/controllers/generic/reconciler/resource_actions_unmanaged_test.go b/internal/controllers/generic/reconciler/resource_actions_unmanaged_test.go new file mode 100644 index 000000000..507256200 --- /dev/null +++ b/internal/controllers/generic/reconciler/resource_actions_unmanaged_test.go @@ -0,0 +1,516 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package reconciler contains integration tests verifying that unmanaged ORC +// resources do not invoke any OpenStack write operations during periodic resync. +// +// Acceptance criteria covered: +// - Unmanaged resources update status without invoking actuator updates. +// - Unmanaged resources still fetch current OpenStack state (read-only). +// - CreateResource is NEVER called for unmanaged resources. +// - Actuator reconcilers (GetResourceReconcilers) are NEVER called for +// unmanaged resources (this is enforced in reconcileNormal). +// +// The tests use thin mock types for the actuator so that any unexpected call to +// a write method (CreateResource) causes the test to fail immediately. +package reconciler + +import ( + "context" + "errors" + "iter" + "testing" + + "github.com/go-logr/logr" + "github.com/gophercloud/gophercloud/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +// -------------------------------------------------------------------------- +// Minimal fake OpenStack resource type used in these tests. +// -------------------------------------------------------------------------- + +// fakeOSResource is a stand-in for any OpenStack resource (e.g. flavors.Flavor). +type fakeOSResource struct { + ID string +} + +// -------------------------------------------------------------------------- +// Mock actuator that enforces "no write operations". +// +// GetOSResourceByID and ListOSResourcesForImport are read-only operations and +// are expected to be called for unmanaged resources. CreateResource is a write +// operation; calling it causes the test to fail immediately. +// -------------------------------------------------------------------------- + +type noWriteActuator struct { + t *testing.T + + // readByIDResult is returned by GetOSResourceByID. + readByIDResult *fakeOSResource + readByIDErr error + + // listResult is returned by ListOSResourcesForImport. + listResult []*fakeOSResource + + // Track which read methods were called so tests can assert that OpenStack + // state was actually fetched. + getByIDCalled bool + listCalled bool +} + +var _ interfaces.CreateResourceActuator[*orcv1alpha1.Flavor, orcv1alpha1.Flavor, orcv1alpha1.FlavorFilter, fakeOSResource] = &noWriteActuator{} + +func (a *noWriteActuator) GetResourceID(r *fakeOSResource) string { + return r.ID +} + +// GetOSResourceByID is a read-only operation: allowed for unmanaged resources. +func (a *noWriteActuator) GetOSResourceByID(_ context.Context, _ string) (*fakeOSResource, progress.ReconcileStatus) { + a.getByIDCalled = true + if a.readByIDErr != nil { + return nil, progress.WrapError(a.readByIDErr) + } + return a.readByIDResult, nil +} + +// ListOSResourcesForAdoption is only called in the creation flow for managed +// resources; for unmanaged resources this path should not be reached when +// statusID or importID is set. +func (a *noWriteActuator) ListOSResourcesForAdoption(_ context.Context, _ *orcv1alpha1.Flavor) (iter.Seq2[*fakeOSResource, error], bool) { + // Return false to signal "no adoption" — this is a safe, read-only path. + return nil, false +} + +// ListOSResourcesForImport is a read-only operation: allowed for unmanaged +// resources using filter-based import. +func (a *noWriteActuator) ListOSResourcesForImport(_ context.Context, _ *orcv1alpha1.Flavor, _ orcv1alpha1.FlavorFilter) (iter.Seq2[*fakeOSResource, error], progress.ReconcileStatus) { + a.listCalled = true + return func(yield func(*fakeOSResource, error) bool) { + for _, r := range a.listResult { + if !yield(r, nil) { + return + } + } + }, nil +} + +// CreateResource is a write operation: MUST NOT be called for unmanaged resources. +func (a *noWriteActuator) CreateResource(_ context.Context, _ *orcv1alpha1.Flavor) (*fakeOSResource, progress.ReconcileStatus) { + a.t.Fatal("CreateResource was called for an unmanaged resource: this is a write operation and MUST NOT be invoked") + return nil, nil +} + +// -------------------------------------------------------------------------- +// fakeAdapter implements interfaces.APIObjectAdapter for *orcv1alpha1.Flavor. +// It delegates all metav1.Object methods to the underlying Flavor (which +// embeds metav1.ObjectMeta and therefore implements metav1.Object). +// -------------------------------------------------------------------------- + +type fakeAdapter struct { + *orcv1alpha1.Flavor +} + +// Ensure fakeAdapter implements APIObjectAdapter at compile time. +var _ interfaces.APIObjectAdapter[*orcv1alpha1.Flavor, orcv1alpha1.FlavorResourceSpec, orcv1alpha1.FlavorFilter] = fakeAdapter{} + +// metav1.Object — all methods delegate to the embedded Flavor (which embeds +// metav1.ObjectMeta). We override only the methods not provided by embedding +// because embedding a non-pointer would copy the object and lose write-backs. + +func (a fakeAdapter) GetUID() types.UID { return a.Flavor.GetUID() } +func (a fakeAdapter) SetUID(uid types.UID) { a.Flavor.SetUID(uid) } +func (a fakeAdapter) GetResourceVersion() string { return a.Flavor.GetResourceVersion() } +func (a fakeAdapter) SetResourceVersion(v string) { a.Flavor.SetResourceVersion(v) } +func (a fakeAdapter) GetGeneration() int64 { return a.Flavor.GetGeneration() } +func (a fakeAdapter) SetGeneration(gen int64) { a.Flavor.SetGeneration(gen) } +func (a fakeAdapter) GetFinalizers() []string { return a.Flavor.GetFinalizers() } +func (a fakeAdapter) SetFinalizers(f []string) { a.Flavor.SetFinalizers(f) } + +// APIObjectAdapter-specific methods. +func (a fakeAdapter) GetObject() *orcv1alpha1.Flavor { return a.Flavor } + +func (a fakeAdapter) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return a.Spec.ManagementPolicy +} + +func (a fakeAdapter) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return a.Spec.ManagedOptions +} + +func (a fakeAdapter) GetResyncPeriod() *metav1.Duration { + return a.Spec.ResyncPeriod +} + +func (a fakeAdapter) GetLastSyncTime() *metav1.Time { + return a.Status.LastSyncTime +} + +func (a fakeAdapter) GetStatusID() *string { + return a.Status.ID +} + +func (a fakeAdapter) GetResourceSpec() *orcv1alpha1.FlavorResourceSpec { + return a.Spec.Resource +} + +func (a fakeAdapter) GetImportID() *string { + if a.Spec.Import == nil { + return nil + } + return a.Spec.Import.ID +} + +func (a fakeAdapter) GetImportFilter() *orcv1alpha1.FlavorFilter { + if a.Spec.Import == nil { + return nil + } + return a.Spec.Import.Filter +} + +// -------------------------------------------------------------------------- +// fakeResourceController satisfies ResourceController for tests that pre-set +// the finalizer on the ORC object so that no Kubernetes Patch is needed. +// -------------------------------------------------------------------------- + +type fakeResourceController struct{} + +var _ ResourceController = &fakeResourceController{} + +func (c *fakeResourceController) GetName() string { return "test-controller" } + +// GetK8sClient returns nil. If a Kubernetes Patch call is reached during a +// test, the nil dereference will cause a panic — signalling a bug in either +// the test setup (finalizer not pre-set) or the reconciler. +func (c *fakeResourceController) GetK8sClient() client.Client { return nil } + +func (c *fakeResourceController) GetScopeFactory() scope.Factory { return nil } + +// -------------------------------------------------------------------------- +// Helpers for building test Flavors. +// +// All helpers pre-set the controller finalizer so that GetOrCreateOSResource +// does not attempt to call the Kubernetes client to add it. +// -------------------------------------------------------------------------- + +const testControllerName = "test-controller" + +// finalizerFor returns the controller finalizer string for testControllerName. +func finalizerFor() string { + return orcstrings.GetFinalizerName(testControllerName) +} + +// unmanagedFlavorWithStatusID builds an unmanaged Flavor whose status.ID is +// already set (the normal periodic-resync case). +func unmanagedFlavorWithStatusID(statusID string) fakeAdapter { + return fakeAdapter{ + Flavor: &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + Finalizers: []string{finalizerFor()}, + }, + Spec: orcv1alpha1.FlavorSpec{ + ManagementPolicy: orcv1alpha1.ManagementPolicyUnmanaged, + Import: &orcv1alpha1.FlavorImport{ + ID: ptr.To(statusID), + }, + }, + Status: orcv1alpha1.FlavorStatus{ + ID: ptr.To(statusID), + }, + }, + } +} + +// unmanagedFlavorWithImportID builds an unmanaged Flavor that specifies an +// importID but has no statusID yet (before first reconcile). +func unmanagedFlavorWithImportID(importID string) fakeAdapter { + return fakeAdapter{ + Flavor: &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + Finalizers: []string{finalizerFor()}, + }, + Spec: orcv1alpha1.FlavorSpec{ + ManagementPolicy: orcv1alpha1.ManagementPolicyUnmanaged, + Import: &orcv1alpha1.FlavorImport{ + ID: ptr.To(importID), + }, + }, + }, + } +} + +// unmanagedFlavorWithFilter builds an unmanaged Flavor using filter-based +// import with no statusID. +func unmanagedFlavorWithFilter(filter orcv1alpha1.FlavorFilter) fakeAdapter { + return fakeAdapter{ + Flavor: &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + Finalizers: []string{finalizerFor()}, + }, + Spec: orcv1alpha1.FlavorSpec{ + ManagementPolicy: orcv1alpha1.ManagementPolicyUnmanaged, + Import: &orcv1alpha1.FlavorImport{ + Filter: &filter, + }, + }, + }, + } +} + +// unmanagedFlavorNoImport builds an unmanaged Flavor with neither statusID nor +// import — an invalid configuration that API validation normally prevents. +func unmanagedFlavorNoImport() fakeAdapter { + return fakeAdapter{ + Flavor: &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + Finalizers: []string{finalizerFor()}, + }, + Spec: orcv1alpha1.FlavorSpec{ + ManagementPolicy: orcv1alpha1.ManagementPolicyUnmanaged, + }, + }, + } +} + +// managedFlavorWithStatusID builds a managed Flavor whose status.ID is already +// set (the normal steady-state case). +func managedFlavorWithStatusID(statusID string) fakeAdapter { + return fakeAdapter{ + Flavor: &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + Finalizers: []string{finalizerFor()}, + }, + Spec: orcv1alpha1.FlavorSpec{ + ManagementPolicy: orcv1alpha1.ManagementPolicyManaged, + Resource: &orcv1alpha1.FlavorResourceSpec{}, + }, + Status: orcv1alpha1.FlavorStatus{ + ID: ptr.To(statusID), + }, + }, + } +} + +// notFoundErr returns a gophercloud not-found error that orcerrors.IsNotFound +// will recognise. +func notFoundErr() error { + return gophercloud.ErrResourceNotFound{Name: "missing-id", ResourceType: "flavor"} +} + +// -------------------------------------------------------------------------- +// Tests +// -------------------------------------------------------------------------- + +// TestGetOrCreateOSResource_UnmanagedByStatusID verifies that for an unmanaged +// resource whose status.ID is already set (the periodic resync case), only +// GetOSResourceByID is called. No write operation (CreateResource) must be +// invoked (unmanaged resources update status without invoking actuator +// updates). +func TestGetOrCreateOSResource_UnmanagedByStatusID(t *testing.T) { + t.Parallel() + + const resourceID = "test-flavor-id" + osResource := &fakeOSResource{ID: resourceID} + + actuator := &noWriteActuator{t: t, readByIDResult: osResource} + adapter := unmanagedFlavorWithStatusID(resourceID) + + got, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + if needsReschedule, err := rs.NeedsReschedule(); needsReschedule { + t.Fatalf("unexpected reconcile status: needsReschedule=%v err=%v", needsReschedule, err) + } + if got == nil || got.ID != resourceID { + t.Errorf("got resource %v, want ID=%q", got, resourceID) + } + // Verify OpenStack state was fetched (acceptance criterion: unmanaged + // resources still fetch current OpenStack state). + if !actuator.getByIDCalled { + t.Error("GetOSResourceByID was not called: unmanaged resources must still fetch current OpenStack state") + } + if actuator.listCalled { + t.Error("ListOSResourcesForImport was unexpectedly called") + } +} + +// TestGetOrCreateOSResource_UnmanagedByImportID verifies that for an unmanaged +// resource using import-by-ID (no statusID yet), GetOSResourceByID is called +// as a read-only operation and CreateResource is never invoked. +func TestGetOrCreateOSResource_UnmanagedByImportID(t *testing.T) { + t.Parallel() + + const importID = "imported-flavor-id" + osResource := &fakeOSResource{ID: importID} + + actuator := &noWriteActuator{t: t, readByIDResult: osResource} + adapter := unmanagedFlavorWithImportID(importID) + + got, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + if needsReschedule, err := rs.NeedsReschedule(); needsReschedule { + t.Fatalf("unexpected reconcile status: needsReschedule=%v err=%v", needsReschedule, err) + } + if got == nil || got.ID != importID { + t.Errorf("got resource %v, want ID=%q", got, importID) + } + if !actuator.getByIDCalled { + t.Error("GetOSResourceByID was not called: unmanaged resources must still fetch current OpenStack state") + } +} + +// TestGetOrCreateOSResource_UnmanagedByFilter verifies that for an unmanaged +// resource using filter-based import, ListOSResourcesForImport is called as a +// read-only operation and CreateResource is never invoked. +func TestGetOrCreateOSResource_UnmanagedByFilter(t *testing.T) { + t.Parallel() + + osResource := &fakeOSResource{ID: "filter-flavor-id"} + filter := orcv1alpha1.FlavorFilter{ + Name: ptr.To[orcv1alpha1.OpenStackName]("my-flavor"), + } + + actuator := &noWriteActuator{t: t, listResult: []*fakeOSResource{osResource}} + adapter := unmanagedFlavorWithFilter(filter) + + got, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + if needsReschedule, err := rs.NeedsReschedule(); needsReschedule { + t.Fatalf("unexpected reconcile status: needsReschedule=%v err=%v", needsReschedule, err) + } + if got == nil || got.ID != osResource.ID { + t.Errorf("got resource %v, want ID=%q", got, osResource.ID) + } + if !actuator.listCalled { + t.Error("ListOSResourcesForImport was not called: unmanaged resources must still fetch current OpenStack state") + } +} + +// TestGetOrCreateOSResource_UnmanagedNoImport verifies that an unmanaged +// resource with no import configuration returns a terminal error without calling +// CreateResource. API validation should prevent this state in +// production, but the reconciler must handle it safely. +func TestGetOrCreateOSResource_UnmanagedNoImport(t *testing.T) { + t.Parallel() + + actuator := &noWriteActuator{t: t} + adapter := unmanagedFlavorNoImport() + + _, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + _, err := rs.NeedsReschedule() + if err == nil { + t.Fatal("expected a terminal error for unmanaged resource with no import, got nil") + } + + // Verify it is a TerminalError so the controller does not retry uselessly. + var termErr *orcerrors.TerminalError + if !errors.As(err, &termErr) { + t.Errorf("expected a TerminalError, got %T: %v", err, err) + } + + if actuator.getByIDCalled { + t.Error("GetOSResourceByID was unexpectedly called") + } + if actuator.listCalled { + t.Error("ListOSResourcesForImport was unexpectedly called") + } +} + +// TestGetOrCreateOSResource_UnmanagedStatusIDDeleted verifies that when an +// unmanaged resource's OpenStack resource has been deleted externally (the +// controller receives a not-found error), the controller returns a terminal +// error rather than calling CreateResource. +func TestGetOrCreateOSResource_UnmanagedStatusIDDeleted(t *testing.T) { + t.Parallel() + + const resourceID = "deleted-flavor-id" + + // Simulate OpenStack returning a 404 / not-found. + actuator := &noWriteActuator{t: t, readByIDErr: notFoundErr()} + adapter := unmanagedFlavorWithStatusID(resourceID) + + _, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + _, err := rs.NeedsReschedule() + if err == nil { + t.Fatal("expected an error when OpenStack resource is not found, got nil") + } + + // The error must be terminal: the resource was deleted externally and cannot + // be recovered by the controller. + var termErr *orcerrors.TerminalError + if !errors.As(err, &termErr) { + t.Errorf("expected a TerminalError for externally-deleted resource, got %T: %v", err, err) + } + + // The controller must still have attempted to fetch the resource. + if !actuator.getByIDCalled { + t.Error("GetOSResourceByID was not called: the controller should attempt to fetch the resource before concluding it is gone") + } +} + +// TestGetOrCreateOSResource_ManagedStatusIDDeleted verifies that when a managed +// resource's OpenStack resource has been deleted externally, the controller +// returns an ExternallyDeleted status to trigger recreation rather than a +// terminal error. +func TestGetOrCreateOSResource_ManagedStatusIDDeleted(t *testing.T) { + t.Parallel() + + const resourceID = "deleted-managed-flavor-id" + + // Simulate OpenStack returning a 404 / not-found. + actuator := &noWriteActuator{t: t, readByIDErr: notFoundErr()} + adapter := managedFlavorWithStatusID(resourceID) + + got, rs := GetOrCreateOSResource(context.Background(), logr.Discard(), &fakeResourceController{}, adapter, actuator) + + // Expect a typed signal: status.id should be cleared and recreation triggered. + if !rs.IsExternallyDeleted() { + t.Fatal("expected IsExternallyDeleted for externally-deleted managed resource") + } + needsReschedule, err := rs.NeedsReschedule() + if needsReschedule { + t.Fatalf("expected no rescheduling (nil reconcileStatus) for externally-deleted managed resource, got needsReschedule=%v err=%v", needsReschedule, err) + } + if got != nil { + t.Errorf("expected nil osResource for recreation path, got %v", got) + } + + // The controller must still have attempted to fetch the resource. + if !actuator.getByIDCalled { + t.Error("GetOSResourceByID was not called") + } +} diff --git a/internal/controllers/generic/resync/config.go b/internal/controllers/generic/resync/config.go new file mode 100644 index 000000000..3b5994962 --- /dev/null +++ b/internal/controllers/generic/resync/config.go @@ -0,0 +1,59 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package resync provides helpers for determining the effective resync period +// for ORC controllers, implementing the configuration resolution hierarchy. +package resync + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// DetermineResyncPeriod resolves the effective resync period using the +// following hierarchy: +// +// 1. If specValue is non-nil and non-zero, return its duration (per-resource +// override takes precedence). +// 2. If specValue is explicitly zero (0s), return 0 (resync is disabled +// regardless of the global default). +// 3. If specValue is nil, return globalDefault. +// +// A return value of 0 means periodic resync is disabled. +func DetermineResyncPeriod(specValue *metav1.Duration, globalDefault time.Duration) time.Duration { + if specValue != nil { + // Explicit spec value: use it unconditionally (zero means disabled). + return specValue.Duration + } + // No per-resource override: fall back to the global default. + return globalDefault +} + +// RemainingUntilNextSync returns how long remains before the next periodic +// resync is due. It returns 0 when periodic resync is disabled, lastSyncTime is +// unset, or the period has already elapsed. +func RemainingUntilNextSync(lastSyncTime *metav1.Time, resyncPeriod time.Duration) time.Duration { + if resyncPeriod <= 0 || lastSyncTime == nil { + return 0 + } + + remaining := resyncPeriod - time.Since(lastSyncTime.Time) + if remaining <= 0 { + return 0 + } + return remaining +} diff --git a/internal/controllers/generic/resync/config_test.go b/internal/controllers/generic/resync/config_test.go new file mode 100644 index 000000000..afa86eaaf --- /dev/null +++ b/internal/controllers/generic/resync/config_test.go @@ -0,0 +1,125 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resync + +import ( + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestDetermineResyncPeriod(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + specValue *metav1.Duration + globalDefault time.Duration + want time.Duration + }{ + { + // spec nil, global disabled → disabled + name: "spec nil, global 0, returns 0 (disabled)", + specValue: nil, + globalDefault: 0, + want: 0, + }, + { + // spec nil, global set → use global + name: "spec nil, global 1h, returns 1h", + specValue: nil, + globalDefault: time.Hour, + want: time.Hour, + }, + { + // spec overrides global + name: "spec 30m, global 1h, returns 30m (spec overrides)", + specValue: &metav1.Duration{Duration: 30 * time.Minute}, + globalDefault: time.Hour, + want: 30 * time.Minute, + }, + { + // explicit 0s in spec disables resync regardless of global + name: "spec 0s (explicit), global 1h, returns 0 (explicitly disabled)", + specValue: &metav1.Duration{Duration: 0}, + globalDefault: time.Hour, + want: 0, + }, + { + // spec enables resync even when global is disabled + name: "spec 2h, global 0, returns 2h (spec enables despite global disabled)", + specValue: &metav1.Duration{Duration: 2 * time.Hour}, + globalDefault: 0, + want: 2 * time.Hour, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got := DetermineResyncPeriod(tt.specValue, tt.globalDefault) + if got != tt.want { + t.Errorf("DetermineResyncPeriod() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestRemainingUntilNextSync(t *testing.T) { + t.Parallel() + + t.Run("disabled", func(t *testing.T) { + t.Parallel() + + lastSync := metav1.NewTime(time.Now().Add(-time.Minute)) + if got := RemainingUntilNextSync(&lastSync, 0); got != 0 { + t.Fatalf("RemainingUntilNextSync() = %v, want 0", got) + } + }) + + t.Run("nil last sync", func(t *testing.T) { + t.Parallel() + + if got := RemainingUntilNextSync(nil, 10*time.Minute); got != 0 { + t.Fatalf("RemainingUntilNextSync() = %v, want 0", got) + } + }) + + t.Run("period elapsed", func(t *testing.T) { + t.Parallel() + + lastSync := metav1.NewTime(time.Now().Add(-20 * time.Minute)) + if got := RemainingUntilNextSync(&lastSync, 10*time.Minute); got != 0 { + t.Fatalf("RemainingUntilNextSync() = %v, want 0", got) + } + }) + + t.Run("period not elapsed", func(t *testing.T) { + t.Parallel() + + lastSync := metav1.NewTime(time.Now().Add(-2 * time.Minute)) + got := RemainingUntilNextSync(&lastSync, 10*time.Minute) + if got <= 0 { + t.Fatalf("RemainingUntilNextSync() = %v, want positive duration", got) + } + if got > 8*time.Minute || got < 7*time.Minute { + t.Fatalf("RemainingUntilNextSync() = %v, want approximately 8m", got) + } + }) +} diff --git a/internal/controllers/generic/resync/scheduler.go b/internal/controllers/generic/resync/scheduler.go new file mode 100644 index 000000000..1530ba323 --- /dev/null +++ b/internal/controllers/generic/resync/scheduler.go @@ -0,0 +1,77 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resync + +import ( + "errors" + "time" + + "k8s.io/apimachinery/pkg/util/wait" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +const ( + // jitterFactor is the maximum fraction of extra time added to the base + // duration. A value of 0.2 produces durations in [base, base*1.2). + // Positive-only jitter ensures the requeue always fires after + // resyncPeriod has elapsed, so shouldReconcile always returns true + // when the requeue fires. + jitterFactor = 0.2 +) + +// CalculateJitteredDuration returns a duration in the range [base, base*1.2) +// using uniform random positive-only jitter. Jitter prevents thundering-herd +// problems when many resources share the same resync period. +func CalculateJitteredDuration(base time.Duration) time.Duration { + return wait.Jitter(base, jitterFactor) +} + +// ShouldScheduleResync reports whether a periodic resync should be scheduled +// based on the effective resync period and the current reconcile status. +// +// It returns false (do not schedule) when: +// - resyncPeriod <= 0: periodic resync is disabled. +// - reconcileStatus contains a terminal error: the resource is in a +// non-retryable error state; resync would be pointless. +// - reconcileStatus already requests a requeue: another reconcile is +// already pending so a resync requeue would be redundant. +// +// When it returns true, the caller should schedule a requeue after +// CalculateJitteredDuration(resyncPeriod). +func ShouldScheduleResync(resyncPeriod time.Duration, reconcileStatus progress.ReconcileStatus) bool { + // Resync disabled. + if resyncPeriod <= 0 { + return false + } + + // Terminal error: no further reconciles will help. + if err := reconcileStatus.GetError(); err != nil { + var terminalError *orcerrors.TerminalError + if errors.As(err, &terminalError) { + return false + } + } + + // Another requeue is already pending; avoid adding a redundant one. + if reconcileStatus.GetRequeue() > 0 { + return false + } + + return true +} diff --git a/internal/controllers/generic/resync/scheduler_test.go b/internal/controllers/generic/resync/scheduler_test.go new file mode 100644 index 000000000..10cf8c92e --- /dev/null +++ b/internal/controllers/generic/resync/scheduler_test.go @@ -0,0 +1,216 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resync + +import ( + "fmt" + "testing" + "time" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// TestCalculateJitteredDuration_Range verifies that the returned duration is +// always within [base*1.0, base*1.2) across many calls (acceptance criterion). +func TestCalculateJitteredDuration_Range(t *testing.T) { + t.Parallel() + + const ( + base = 10 * time.Minute + samples = 1000 + ) + + lo := time.Duration(float64(base) * 1.0) + hi := time.Duration(float64(base) * 1.2) + + for i := range samples { + d := CalculateJitteredDuration(base) + if d < lo || d > hi { + t.Errorf("sample %d: CalculateJitteredDuration(%v) = %v, want in [%v, %v]", i, base, d, lo, hi) + } + } +} + +// TestCalculateJitteredDuration_Uniformity verifies that the jitter +// distribution is statistically uniform by checking that all 10 buckets across +// [base*1.0, base*1.2) are populated with at least 1/20th of the expected +// frequency (very conservative check to avoid flakiness while still catching +// obvious bias). +func TestCalculateJitteredDuration_Uniformity(t *testing.T) { + t.Parallel() + + const ( + base = time.Hour + samples = 10000 + buckets = 10 + ) + + lo := float64(base) * 1.0 + hi := float64(base) * (1 + jitterFactor) + width := (hi - lo) / buckets + + counts := make([]int, buckets) + for range samples { + d := CalculateJitteredDuration(base) + idx := int((float64(d) - lo) / width) + // Clamp to handle floating-point edge at the top of the range. + if idx >= buckets { + idx = buckets - 1 + } + if idx < 0 { + idx = 0 + } + counts[idx]++ + } + + // Each bucket should receive roughly samples/buckets hits. Require at + // least 1/3 of the expected count to avoid flakiness while catching bias. + minExpected := (samples / buckets) / 3 + for i, c := range counts { + if c < minExpected { + t.Errorf("bucket %d: count %d is below minimum expected %d (distribution is not uniform)", i, c, minExpected) + } + } +} + +// TestCalculateJitteredDuration_Independence verifies that multiple resources +// receive independent jitter values: calling the function twice with +// the same base should produce different values in the vast majority of cases. +func TestCalculateJitteredDuration_Independence(t *testing.T) { + t.Parallel() + + const ( + base = time.Hour + samples = 100 + ) + + unique := make(map[time.Duration]struct{}, samples) + for range samples { + d := CalculateJitteredDuration(base) + unique[d] = struct{}{} + } + + // Expect nearly all samples to be distinct. Allow for at most 5% + // collisions (extremely conservative; in practice collisions are + // essentially impossible with nanosecond precision). + minUnique := samples * 95 / 100 + if len(unique) < minUnique { + t.Errorf("CalculateJitteredDuration produced only %d unique values out of %d samples (expected >= %d); values may not be independent", len(unique), samples, minUnique) + } +} + +// TestCalculateJitteredDuration_ZeroBase verifies behaviour with a zero base. +func TestCalculateJitteredDuration_ZeroBase(t *testing.T) { + t.Parallel() + + if d := CalculateJitteredDuration(0); d != 0 { + t.Errorf("CalculateJitteredDuration(0) = %v, want 0", d) + } +} + +// TestShouldScheduleResync covers all documented return-false conditions and +// the happy path. +func TestShouldScheduleResync(t *testing.T) { + t.Parallel() + + terminalErr := orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "bad config") + transientErr := fmt.Errorf("transient error") + + tests := []struct { + name string + resyncPeriod time.Duration + reconcileStatus progress.ReconcileStatus + want bool + }{ + { + // resync disabled globally + name: "resyncPeriod 0, nil status, returns false", + resyncPeriod: 0, + reconcileStatus: nil, + want: false, + }, + { + // resyncPeriod negative: treated as disabled + name: "resyncPeriod negative, nil status, returns false", + resyncPeriod: -time.Second, + reconcileStatus: nil, + want: false, + }, + { + // terminal error → no resync + name: "terminal error in status, returns false", + resyncPeriod: time.Hour, + reconcileStatus: progress.WrapError(terminalErr), + want: false, + }, + { + // requeue already pending → resync is redundant + name: "requeue already pending in status, returns false", + resyncPeriod: time.Hour, + reconcileStatus: progress.NewReconcileStatus().WithRequeue(5 * time.Second), + want: false, + }, + { + // Happy path: positive period, no terminal error, no pending requeue + name: "positive period, nil status, returns true", + resyncPeriod: time.Hour, + reconcileStatus: nil, + want: true, + }, + { + // Happy path: transient (non-terminal) error should not suppress resync + name: "transient error in status, returns true", + resyncPeriod: time.Hour, + reconcileStatus: progress.WrapError(transientErr), + want: true, + }, + { + // Happy path: progress message with no requeue should not suppress resync + name: "progress message only, no requeue, returns true", + resyncPeriod: time.Hour, + reconcileStatus: progress.NewReconcileStatus().WithProgressMessage("waiting for dependency"), + want: true, + }, + { + // Terminal error takes precedence even when period is positive + name: "terminal error with progress message, returns false", + resyncPeriod: time.Hour, + reconcileStatus: progress.WrapError(terminalErr).WithProgressMessage("some message"), + want: false, + }, + { + // Requeue takes precedence when period is positive + name: "requeue pending with progress message, returns false", + resyncPeriod: 30 * time.Minute, + reconcileStatus: progress.NewReconcileStatus().WithRequeue(10 * time.Second).WithProgressMessage("waiting"), + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got := ShouldScheduleResync(tt.resyncPeriod, tt.reconcileStatus) + if got != tt.want { + t.Errorf("ShouldScheduleResync(%v, ...) = %v, want %v", tt.resyncPeriod, got, tt.want) + } + }) + } +} diff --git a/internal/controllers/generic/status/conditions.go b/internal/controllers/generic/status/conditions.go index 9ac683150..b154509f1 100644 --- a/internal/controllers/generic/status/conditions.go +++ b/internal/controllers/generic/status/conditions.go @@ -40,6 +40,15 @@ func SetCommonConditions[T any]( reconcileStatus progress.ReconcileStatus, now metav1.Time, ) { + // Terminal errors make the resource definitively unavailable. + // Override Unknown → False so Available matches the error severity. + if availableStatus != metav1.ConditionTrue { + var terminalErr *orcerrors.TerminalError + if errors.As(reconcileStatus.GetError(), &terminalErr) { + availableStatus = metav1.ConditionFalse + } + } + availableCondition := applyconfigv1.Condition(). WithType(orcv1alpha1.ConditionAvailable). WithStatus(availableStatus). diff --git a/internal/controllers/generic/status/conditions_test.go b/internal/controllers/generic/status/conditions_test.go new file mode 100644 index 000000000..ba821d02e --- /dev/null +++ b/internal/controllers/generic/status/conditions_test.go @@ -0,0 +1,155 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package status + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +// TestSetCommonConditions_TerminalErrorOverridesUnknownToFalse verifies that +// when ResourceAvailableStatus returns ConditionUnknown and a terminal error is +// present, SetCommonConditions overrides the Available condition to False. +// +// This is the fix for the network-external-deletion-import CI failure: when an +// imported network is externally deleted, ORC sets a terminal error but +// ResourceAvailableStatus returns ConditionUnknown (because Status.ID is set +// but the OS resource is nil). The Available condition must be False, not +// Unknown, when a terminal error is present. +func TestSetCommonConditions_TerminalErrorOverridesUnknownToFalse(t *testing.T) { + t.Parallel() + + flavor := &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + }, + } + + termErr := orcerrors.Terminal(orcv1alpha1.ConditionReasonUnrecoverableError, "resource has been deleted from OpenStack", nil) + reconcileStatus := progress.WrapError(termErr) + + applyConfigStatus := orcapplyconfigv1alpha1.FlavorStatus() + now := metav1.Now() + + // Call SetCommonConditions with ConditionUnknown (as ResourceAvailableStatus + // returns when osResource==nil and Status.ID!=nil) and a terminal error. + SetCommonConditions(flavor, applyConfigStatus, metav1.ConditionUnknown, reconcileStatus, now) + + // Find the Available condition in the resulting apply configuration. + var availableCondition *metav1.ConditionStatus + for i := range applyConfigStatus.Conditions { + if applyConfigStatus.Conditions[i].Type != nil && *applyConfigStatus.Conditions[i].Type == orcv1alpha1.ConditionAvailable { + availableCondition = applyConfigStatus.Conditions[i].Status + break + } + } + + if availableCondition == nil { + t.Fatal("Available condition not set in apply configuration") + } + + if *availableCondition != metav1.ConditionFalse { + t.Errorf("Available condition status = %q; want %q (terminal error should override Unknown → False)", + *availableCondition, metav1.ConditionFalse) + } +} + +// TestSetCommonConditions_TerminalErrorWithFalseRemainingFalse verifies that +// when ResourceAvailableStatus already returns ConditionFalse and a terminal +// error is present, the Available condition remains False (not changed). +func TestSetCommonConditions_TerminalErrorWithFalseRemainingFalse(t *testing.T) { + t.Parallel() + + flavor := &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + }, + } + + termErr := orcerrors.Terminal(orcv1alpha1.ConditionReasonUnrecoverableError, "resource has been deleted from OpenStack", nil) + reconcileStatus := progress.WrapError(termErr) + + applyConfigStatus := orcapplyconfigv1alpha1.FlavorStatus() + now := metav1.Now() + + // Call SetCommonConditions with ConditionFalse (resource not found, no ID). + SetCommonConditions(flavor, applyConfigStatus, metav1.ConditionFalse, reconcileStatus, now) + + var availableCondition *metav1.ConditionStatus + for i := range applyConfigStatus.Conditions { + if applyConfigStatus.Conditions[i].Type != nil && *applyConfigStatus.Conditions[i].Type == orcv1alpha1.ConditionAvailable { + availableCondition = applyConfigStatus.Conditions[i].Status + break + } + } + + if availableCondition == nil { + t.Fatal("Available condition not set in apply configuration") + } + + if *availableCondition != metav1.ConditionFalse { + t.Errorf("Available condition status = %q; want %q", *availableCondition, metav1.ConditionFalse) + } +} + +// TestSetCommonConditions_NoTerminalErrorKeepsUnknown verifies that when +// ResourceAvailableStatus returns ConditionUnknown and no terminal error is +// present (e.g. a transient error or progress), the Available condition remains +// Unknown. +func TestSetCommonConditions_NoTerminalErrorKeepsUnknown(t *testing.T) { + t.Parallel() + + flavor := &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + }, + } + + // Transient error (not terminal) — Available should remain Unknown. + reconcileStatus := progress.NewReconcileStatus().WithProgressMessage("waiting for OpenStack") + + applyConfigStatus := orcapplyconfigv1alpha1.FlavorStatus() + now := metav1.Now() + + SetCommonConditions(flavor, applyConfigStatus, metav1.ConditionUnknown, reconcileStatus, now) + + var availableCondition *metav1.ConditionStatus + for i := range applyConfigStatus.Conditions { + if applyConfigStatus.Conditions[i].Type != nil && *applyConfigStatus.Conditions[i].Type == orcv1alpha1.ConditionAvailable { + availableCondition = applyConfigStatus.Conditions[i].Status + break + } + } + + if availableCondition == nil { + t.Fatal("Available condition not set in apply configuration") + } + + if *availableCondition != metav1.ConditionUnknown { + t.Errorf("Available condition status = %q; want %q (no terminal error should not change Unknown)", + *availableCondition, metav1.ConditionUnknown) + } +} diff --git a/internal/controllers/generic/status/status.go b/internal/controllers/generic/status/status.go index 4776d16ae..f2c3c4d39 100644 --- a/internal/controllers/generic/status/status.go +++ b/internal/controllers/generic/status/status.go @@ -41,7 +41,7 @@ func SetStatusID[ objectApplyPT interfaces.ORCApplyConfig[objectApplyPT, statusApplyPT], statusApplyPT interface { *statusApplyT - interfaces.ORCStatusApplyConfig[statusApplyPT] + interfaces.ORCStatusApplyConfigWithID[statusApplyPT] }, statusApplyT any, osResourcePT any, @@ -62,6 +62,28 @@ func SetStatusID[ return controller.GetK8sClient().Status().Patch(ctx, orcObject, applyconfigs.Patch(types.MergePatchType, applyConfig)) } +// ClearStatusID clears the status.id field of an ORC object using a JSON merge +// patch. This is necessary when an externally deleted managed resource is +// detected: clearing the ID allows the next reconciliation to enter the +// standard creation path and assign a new ID after the resource is recreated. +// +// A JSON merge patch with an explicit null value is required because the +// generated apply configuration types use omitempty on the ID field, meaning a +// nil pointer would simply omit the field rather than clear it. +func ClearStatusID(ctx context.Context, controller interfaces.ResourceController, orcObject client.Object) error { + patch := client.RawPatch(types.MergePatchType, []byte(`{"status":{"id":null}}`)) + return controller.GetK8sClient().Status().Patch(ctx, orcObject, patch) +} + +// shouldSetLastSyncTime reports whether lastSyncTime should be set on a status +// update. It returns true only when the reconciliation completed successfully: +// the reconcileStatus contains neither errors nor progress messages. A requeue +// alone (e.g., for a periodic resync) does not prevent the update. +func shouldSetLastSyncTime(reconcileStatus progress.ReconcileStatus) bool { + needsReschedule, _ := reconcileStatus.NeedsReschedule() + return !needsReschedule +} + func UpdateStatus[ orcObjectPT interface { client.Object @@ -70,7 +92,7 @@ func UpdateStatus[ osResourcePT *osResourceT, objectApplyPT interfaces.ORCApplyConfig[objectApplyPT, statusApplyPT], statusApplyPT interface { - interfaces.ORCStatusApplyConfig[statusApplyPT] + interfaces.ORCStatusApplyConfigWithLastSyncTime[statusApplyPT] *statusApply }, statusApply any, @@ -100,6 +122,13 @@ func UpdateStatus[ reconcileStatus = reconcileStatus.WithReconcileStatus(availableReconcileStatus) SetCommonConditions(orcObject, applyConfigStatus, available, reconcileStatus, now) + // Set lastSyncTime only on successful reconciliation: no errors and no + // progress messages indicate that the controller successfully fetched the + // resource state from OpenStack. + if shouldSetLastSyncTime(reconcileStatus) { + applyConfigStatus.WithLastSyncTime(now) + } + // Patch orcObject with the status transaction k8sClient := controller.GetK8sClient() ssaFieldOwner := orcstrings.GetSSAFieldOwnerWithTxn(controller.GetName(), orcstrings.SSATransactionStatus) diff --git a/internal/controllers/generic/status/status_test.go b/internal/controllers/generic/status/status_test.go new file mode 100644 index 000000000..18d031624 --- /dev/null +++ b/internal/controllers/generic/status/status_test.go @@ -0,0 +1,228 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package status + +import ( + "context" + "errors" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// TestShouldSetLastSyncTime_SuccessfulReconciliation verifies that lastSyncTime +// is set when reconcileStatus is nil (clean success, no errors, no progress +// messages). This is the common case after a successful OpenStack API read. +func TestShouldSetLastSyncTime_SuccessfulReconciliation(t *testing.T) { + t.Parallel() + + // nil ReconcileStatus represents a clean, successful reconciliation. + var rs progress.ReconcileStatus + if !shouldSetLastSyncTime(rs) { + t.Error("shouldSetLastSyncTime(nil) = false; want true for successful reconciliation") + } +} + +// TestShouldSetLastSyncTime_WithRequeueOnly verifies that a requeue alone +// (e.g., for a periodic resync) does not prevent lastSyncTime from being set. +// A pending requeue without errors or progress messages still counts as a +// successful reconciliation cycle. +func TestShouldSetLastSyncTime_WithRequeueOnly(t *testing.T) { + t.Parallel() + + // A requeue alone does not contribute to NeedsReschedule. + rs := progress.NewReconcileStatus().WithRequeue(10 * time.Minute) + if !shouldSetLastSyncTime(rs) { + t.Error("shouldSetLastSyncTime(requeue-only) = false; want true: requeue alone should not prevent lastSyncTime update") + } +} + +// TestShouldSetLastSyncTime_WithError verifies that lastSyncTime is NOT set +// when reconcileStatus contains an error. An error means the controller did not +// successfully complete the reconciliation cycle. +func TestShouldSetLastSyncTime_WithError(t *testing.T) { + t.Parallel() + + rs := progress.WrapError(errors.New("transient openstack error")) + if shouldSetLastSyncTime(rs) { + t.Error("shouldSetLastSyncTime(error) = true; want false: errors should prevent lastSyncTime update") + } +} + +// TestShouldSetLastSyncTime_WithTerminalError verifies that lastSyncTime is NOT +// set when reconcileStatus contains a terminal error. Terminal errors indicate +// a non-retryable failure; the reconciliation did not succeed. +func TestShouldSetLastSyncTime_WithTerminalError(t *testing.T) { + t.Parallel() + + termErr := orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration", nil) + rs := progress.WrapError(termErr) + if shouldSetLastSyncTime(rs) { + t.Error("shouldSetLastSyncTime(terminal error) = true; want false: terminal errors should prevent lastSyncTime update") + } +} + +// TestShouldSetLastSyncTime_WithProgressMessage verifies that lastSyncTime is +// NOT set when reconcileStatus contains a progress message. Progress messages +// indicate that the reconciliation is still ongoing (waiting on a dependency, +// resource not yet ready, etc.) and has not completed successfully. +func TestShouldSetLastSyncTime_WithProgressMessage(t *testing.T) { + t.Parallel() + + rs := progress.NewReconcileStatus().WithProgressMessage("waiting for resource to become active") + if shouldSetLastSyncTime(rs) { + t.Error("shouldSetLastSyncTime(progress message) = true; want false: progress messages should prevent lastSyncTime update") + } +} + +// TestShouldSetLastSyncTime_WithErrorAndProgressMessage verifies that +// lastSyncTime is NOT set when reconcileStatus contains both an error and a +// progress message. Either alone should be sufficient to suppress the update. +func TestShouldSetLastSyncTime_WithErrorAndProgressMessage(t *testing.T) { + t.Parallel() + + rs := progress.WrapError(errors.New("API error")).WithProgressMessage("still waiting") + if shouldSetLastSyncTime(rs) { + t.Error("shouldSetLastSyncTime(error+progress) = true; want false: any non-success condition should prevent lastSyncTime update") + } +} + +// -------------------------------------------------------------------------- +// fakeStatusController implements interfaces.ResourceController for +// ClearStatusID tests. It wraps a real fake.Client to allow status patch calls. +// -------------------------------------------------------------------------- + +type fakeStatusController struct { + k8sClient client.Client +} + +var _ interfaces.ResourceController = &fakeStatusController{} + +func (c *fakeStatusController) GetName() string { return "test-status-controller" } +func (c *fakeStatusController) GetK8sClient() client.Client { return c.k8sClient } +func (c *fakeStatusController) GetScopeFactory() scope.Factory { return nil } + +// TestClearStatusID_SendsMergePatchWithNullID verifies that ClearStatusID +// issues a JSON merge patch that sets status.id to null. The function is +// expected to be called by reconcileNormal when an externally deleted managed +// resource is detected (GetOrCreateOSResource returns nil, nil). +func TestClearStatusID_SendsMergePatchWithNullID(t *testing.T) { + t.Parallel() + + const resourceID = "some-os-id" + + // Build a Flavor with status.ID already set (simulating a managed resource + // whose OpenStack counterpart was deleted externally). + flavor := &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + UID: types.UID("test-uid"), + }, + Status: orcv1alpha1.FlavorStatus{ + ID: ptr.To(resourceID), + }, + } + + // Register the Flavor scheme so the fake client can handle it. + scheme := runtime.NewScheme() + if err := orcv1alpha1.AddToScheme(scheme); err != nil { + t.Fatalf("failed to add orcv1alpha1 to scheme: %v", err) + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithStatusSubresource(&orcv1alpha1.Flavor{}). + WithObjects(flavor). + Build() + + controller := &fakeStatusController{k8sClient: fakeClient} + + // Call ClearStatusID: should patch status.id to null. + if err := ClearStatusID(context.Background(), controller, flavor); err != nil { + t.Fatalf("ClearStatusID returned unexpected error: %v", err) + } + + // Fetch the updated Flavor and verify status.ID is now nil. + updated := &orcv1alpha1.Flavor{} + if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "test-flavor", Namespace: "default"}, updated); err != nil { + t.Fatalf("failed to get updated flavor: %v", err) + } + + if updated.Status.ID != nil { + t.Errorf("status.id = %q after ClearStatusID; want nil (cleared)", *updated.Status.ID) + } +} + +// TestClearStatusID_GroupVersionResource verifies that ClearStatusID targets +// the status subresource (i.e., calls Status().Patch rather than Patch). +// This is an indirect check: if ClearStatusID called the main Patch instead of +// Status().Patch, the fake client with WithStatusSubresource would not update +// the status and the ID would remain set. +func TestClearStatusID_IdempotentWhenAlreadyNil(t *testing.T) { + t.Parallel() + + // Flavor with no status.ID (already cleared or never set). + flavor := &orcv1alpha1.Flavor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-flavor", + Namespace: "default", + UID: types.UID("test-uid"), + }, + // Status.ID is nil by default. + } + + scheme := runtime.NewScheme() + if err := orcv1alpha1.AddToScheme(scheme); err != nil { + t.Fatalf("failed to add orcv1alpha1 to scheme: %v", err) + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithStatusSubresource(&orcv1alpha1.Flavor{}). + WithObjects(flavor). + Build() + + controller := &fakeStatusController{k8sClient: fakeClient} + + // ClearStatusID should succeed even when status.id is already nil. + if err := ClearStatusID(context.Background(), controller, flavor); err != nil { + t.Fatalf("ClearStatusID returned unexpected error on already-nil ID: %v", err) + } + + // Status.ID should remain nil. + updated := &orcv1alpha1.Flavor{} + if err := fakeClient.Get(context.Background(), client.ObjectKey{Name: "test-flavor", Namespace: "default"}, updated); err != nil { + t.Fatalf("failed to get flavor after ClearStatusID: %v", err) + } + + if updated.Status.ID != nil { + t.Errorf("status.id = %q after ClearStatusID on already-nil ID; want nil", *updated.Status.ID) + } +} diff --git a/internal/controllers/group/actuator.go b/internal/controllers/group/actuator.go index 268cd2fd3..87e84a3e1 100644 --- a/internal/controllers/group/actuator.go +++ b/internal/controllers/group/actuator.go @@ -18,12 +18,10 @@ package group import ( "context" - "fmt" "iter" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/groups" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -33,6 +31,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" ) @@ -72,8 +71,25 @@ func (actuator groupActuator) ListOSResourcesForAdoption(ctx context.Context, or return nil, false } + // Resolve the domain ID from DomainRef if set. Without the domain + // ID, adoption could match a group in the wrong domain. + var domainID string + if resourceSpec.DomainRef != nil { + domain, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.DomainRef, "Domain", + func(dep *orcv1alpha1.Domain) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + domainID = ptr.Deref(domain.Status.ID, "") + } + listOpts := groups.ListOpts{ - Name: getResourceName(orcObject), + Name: getResourceName(orcObject), + DomainID: domainID, } return actuator.osClient.ListGroups(ctx, listOpts), true @@ -83,24 +99,11 @@ func (actuator groupActuator) ListOSResourcesForImport(ctx context.Context, obj var reconcileStatus progress.ReconcileStatus - domain := &orcv1alpha1.Domain{} - if filter.DomainRef != nil { - domainKey := client.ObjectKey{Name: string(*filter.DomainRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, domainKey, domain); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Domain", domainKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching domain %s: %w", domainKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(domain) || domain.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Domain", domainKey.Name, progress.WaitingOnReady)) - } - } - } + domain, rs := dependency.FetchDependency[*orcv1alpha1.Domain]( + ctx, actuator.k8sClient, obj.Namespace, filter.DomainRef, "Domain", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -127,9 +130,7 @@ func (actuator groupActuator) CreateResource(ctx context.Context, obj orcObjectP var domainID string if resource.DomainRef != nil { domain, domainDepRS := domainDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Domain) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(domainDepRS) if domain != nil { @@ -187,12 +188,10 @@ func (actuator groupActuator) updateResource(ctx context.Context, obj orcObjectP _, err = actuator.osClient.UpdateGroup(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/group/controller.go b/internal/controllers/group/controller.go index 043a22e44..b5378e044 100644 --- a/internal/controllers/group/controller.go +++ b/internal/controllers/group/controller.go @@ -19,6 +19,7 @@ package group import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -40,17 +41,22 @@ const controllerName = "group" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=groups/status,verbs=get;update;patch type groupReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return groupReconcilerConstructor{scopeFactory: scopeFactory} + return &groupReconcilerConstructor{scopeFactory: scopeFactory} } func (groupReconcilerConstructor) GetName() string { return controllerName } +func (c *groupReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + var domainDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.GroupList, *orcv1alpha1.Domain]( "spec.resource.domainRef", func(group *orcv1alpha1.Group) []string { @@ -75,7 +81,7 @@ var domainImportDependency = dependency.NewDependency[*orcv1alpha1.GroupList, *o ) // SetupWithManager sets up the controller with the Manager. -func (c groupReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *groupReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) k8sClient := mgr.GetClient() @@ -109,6 +115,6 @@ func (c groupReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ct return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, groupHelperFactory{}, groupStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, groupHelperFactory{}, groupStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/group/zz_generated.adapter.go b/internal/controllers/group/zz_generated.adapter.go index 48d281caf..10748fe6d 100644 --- a/internal/controllers/group/zz_generated.adapter.go +++ b/internal/controllers/group/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package group import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/group/zz_generated.controller.go b/internal/controllers/group/zz_generated.controller.go index 572c0f289..39e06261a 100644 --- a/internal/controllers/group/zz_generated.controller.go +++ b/internal/controllers/group/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/image/actuator.go b/internal/controllers/image/actuator.go index fd40daaa8..b733bb3b7 100644 --- a/internal/controllers/image/actuator.go +++ b/internal/controllers/image/actuator.go @@ -171,9 +171,11 @@ func (actuator imageActuator) CreateResource(ctx context.Context, obj *orcv1alph Properties: additionalProperties, }) - // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating image: "+err.Error(), err) + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating image: "+err.Error(), err) + } + return nil, progress.WrapError(err) } if err != nil { @@ -208,10 +210,10 @@ func (actuator imageActuator) UpdateResource(ctx context.Context, obj orcObjectP _, err := actuator.osClient.UpdateImage(ctx, osResource.ID, updateOpts) - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/image/controller.go b/internal/controllers/image/controller.go index 2416fa823..f70f3ccdf 100644 --- a/internal/controllers/image/controller.go +++ b/internal/controllers/image/controller.go @@ -49,19 +49,24 @@ const ( ) type imageReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return imageReconcilerConstructor{scopeFactory: scopeFactory} + return &imageReconcilerConstructor{scopeFactory: scopeFactory} } func (imageReconcilerConstructor) GetName() string { return controllerName } +func (c *imageReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c imageReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *imageReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) builder := ctrl.NewControllerManagedBy(mgr). @@ -75,6 +80,6 @@ func (c imageReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ct return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, imageHelperFactory{}, imageStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, imageHelperFactory{}, imageStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/image/suite_test.go b/internal/controllers/image/suite_test.go index 4b1fa4de2..5803d580f 100644 --- a/internal/controllers/image/suite_test.go +++ b/internal/controllers/image/suite_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + utilrand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -82,7 +83,7 @@ var _ = Describe("EnvTest sanity check", func() { It("should be able to create a namespace", func() { ctx := context.TODO() namespace := &corev1.Namespace{} - namespace.SetGenerateName("test-") + namespace.SetName("test-" + utilrand.String(10)) // Create the namespace Expect(k8sClient.Create(ctx, namespace)).To(Succeed(), "create namespace") diff --git a/internal/controllers/image/upload_test.go b/internal/controllers/image/upload_test.go index cfdb2a5f5..3a2f92565 100644 --- a/internal/controllers/image/upload_test.go +++ b/internal/controllers/image/upload_test.go @@ -28,6 +28,7 @@ import ( . "github.com/onsi/gomega" "go.uber.org/mock/gomock" corev1 "k8s.io/api/core/v1" + utilrand "k8s.io/apimachinery/pkg/util/rand" ctrl "sigs.k8s.io/controller-runtime" orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" @@ -158,7 +159,7 @@ var _ = Describe("Upload tests", Ordered, func() { // Create the namespace namespace = &corev1.Namespace{} - namespace.SetGenerateName("test-") + namespace.SetName("test-" + utilrand.String(10)) Expect(k8sClient.Create(ctx, namespace)).To(Succeed(), "create namespace") DeferCleanup(func() { Expect(k8sClient.Delete(ctx, namespace)).To(Succeed(), "delete namespace") diff --git a/internal/controllers/image/zz_generated.adapter.go b/internal/controllers/image/zz_generated.adapter.go index c81752969..5fa2b7639 100644 --- a/internal/controllers/image/zz_generated.adapter.go +++ b/internal/controllers/image/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package image import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/image/zz_generated.controller.go b/internal/controllers/image/zz_generated.controller.go index 73bfa7160..a980a5c4f 100644 --- a/internal/controllers/image/zz_generated.controller.go +++ b/internal/controllers/image/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/keypair/actuator.go b/internal/controllers/keypair/actuator.go index d5ecc34f5..b11d361ab 100644 --- a/internal/controllers/keypair/actuator.go +++ b/internal/controllers/keypair/actuator.go @@ -78,10 +78,11 @@ func (actuator keypairActuator) ListOSResourcesForAdoption(ctx context.Context, // Filter by the expected resource name to avoid adopting wrong keypairs. // The OpenStack Keypairs API does not support server-side filtering by name, // so we must use client-side filtering. - var filters []osclients.ResourceFilter[osResourceT] - filters = append(filters, func(kp *keypairs.KeyPair) bool { - return kp.Name == getResourceName(orcObject) - }) + filters := []osclients.ResourceFilter[osResourceT]{ + func(kp *keypairs.KeyPair) bool { + return kp.Name == getResourceName(orcObject) + }, + } return actuator.listOSResources(ctx, filters, keypairs.ListOpts{}), true } diff --git a/internal/controllers/keypair/controller.go b/internal/controllers/keypair/controller.go index 64cc7cb73..2d14c04cd 100644 --- a/internal/controllers/keypair/controller.go +++ b/internal/controllers/keypair/controller.go @@ -19,6 +19,7 @@ package keypair import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -37,19 +38,24 @@ const controllerName = "keypair" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=keypairs/status,verbs=get;update;patch type keypairReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return keypairReconcilerConstructor{scopeFactory: scopeFactory} + return &keypairReconcilerConstructor{scopeFactory: scopeFactory} } func (keypairReconcilerConstructor) GetName() string { return controllerName } +func (c *keypairReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c keypairReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *keypairReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) builder := ctrl.NewControllerManagedBy(mgr). @@ -63,6 +69,6 @@ func (c keypairReconcilerConstructor) SetupWithManager(ctx context.Context, mgr return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, keypairHelperFactory{}, keypairStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, keypairHelperFactory{}, keypairStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/keypair/zz_generated.adapter.go b/internal/controllers/keypair/zz_generated.adapter.go index 9b71b893a..0cb2ae1a5 100644 --- a/internal/controllers/keypair/zz_generated.adapter.go +++ b/internal/controllers/keypair/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package keypair import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/keypair/zz_generated.controller.go b/internal/controllers/keypair/zz_generated.controller.go index 95bb9f371..c3bdcda17 100644 --- a/internal/controllers/keypair/zz_generated.controller.go +++ b/internal/controllers/keypair/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/network/actuator.go b/internal/controllers/network/actuator.go index 8d7f1eeed..d6b9b273c 100644 --- a/internal/controllers/network/actuator.go +++ b/internal/controllers/network/actuator.go @@ -18,7 +18,6 @@ package network import ( "context" - "fmt" "iter" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/dns" @@ -27,7 +26,6 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsecurity" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -37,6 +35,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" ) @@ -73,35 +72,43 @@ func (actuator networkActuator) GetOSResourceByID(ctx context.Context, id string } func (actuator networkActuator) ListOSResourcesForAdoption(ctx context.Context, obj orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { - if obj.Spec.Resource == nil { + resource := obj.Spec.Resource + if resource == nil { return nil, false } - listOpts := networks.ListOpts{Name: getResourceName(obj)} + // Resolve the project ID from ProjectRef if set. Without the project + // ID, adoption with admin-scoped credentials could match a network + // in the wrong project. + var projectID string + if resource.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + + listOpts := networks.ListOpts{ + Name: getResourceName(obj), + ProjectID: projectID, + } return actuator.osClient.ListNetwork(ctx, listOpts), true } func (actuator networkActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { var reconcileStatus progress.ReconcileStatus - project := &orcv1alpha1.Project{} - if filter.ProjectRef != nil { - projectKey := client.ObjectKey{Name: string(*filter.ProjectRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, projectKey, project); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching project %s: %w", projectKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(project) || project.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnReady)) - } - } - } + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -130,9 +137,7 @@ func (actuator networkActuator) CreateResource(ctx context.Context, obj orcObjec var projectID string if resource.ProjectRef != nil { project, reconcileStatus := projectDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Project) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -189,8 +194,8 @@ func (actuator networkActuator) CreateResource(ctx context.Context, obj orcObjec osResource, err := actuator.osClient.CreateNetwork(ctx, createOpts) if err != nil { - // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsConflict(err) { + // We should require the spec to be updated before retrying a create which returned a non-retryable error + if !orcerrors.IsRetryable(err) { err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) } return nil, progress.WrapError(err) @@ -246,10 +251,10 @@ func (actuator networkActuator) updateResource(ctx context.Context, obj orcObjec _, err = actuator.osClient.UpdateNetwork(ctx, osResource.ID, updateOpts) - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/network/controller.go b/internal/controllers/network/controller.go index a9795133e..f08fdaf0f 100644 --- a/internal/controllers/network/controller.go +++ b/internal/controllers/network/controller.go @@ -19,6 +19,7 @@ package network import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -65,11 +66,12 @@ var ( ) type networkReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return networkReconcilerConstructor{ + return &networkReconcilerConstructor{ scopeFactory: scopeFactory, } } @@ -78,8 +80,12 @@ func (networkReconcilerConstructor) GetName() string { return controllerName } +func (c *networkReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c networkReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *networkReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) k8sClient := mgr.GetClient() @@ -113,6 +119,6 @@ func (c networkReconcilerConstructor) SetupWithManager(ctx context.Context, mgr return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, networkHelperFactory{}, networkStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, networkHelperFactory{}, networkStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/network/tests/network-external-deletion-import/00-assert.yaml b/internal/controllers/network/tests/network-external-deletion-import/00-assert.yaml new file mode 100644 index 000000000..1a9230468 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/00-assert.yaml @@ -0,0 +1,14 @@ +--- +# Verify the external network is available before proceeding with the import. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion-import-external +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/network/tests/network-external-deletion-import/00-create-external.yaml b/internal/controllers/network/tests/network-external-deletion-import/00-create-external.yaml new file mode 100644 index 000000000..124ecc841 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/00-create-external.yaml @@ -0,0 +1,15 @@ +--- +# Create a managed network in OpenStack via ORC. This network will later be +# imported as an unmanaged resource, then deleted externally to verify that +# ORC produces a terminal error (rather than recreating it). +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion-import-external +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Network from "external-deletion-import" test diff --git a/internal/controllers/network/tests/network-external-deletion-import/00-secret.yaml b/internal/controllers/network/tests/network-external-deletion-import/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/network/tests/network-external-deletion-import/01-assert.yaml b/internal/controllers/network/tests/network-external-deletion-import/01-assert.yaml new file mode 100644 index 000000000..4429a2653 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/01-assert.yaml @@ -0,0 +1,22 @@ +--- +# Verify the imported network is available, confirming the import succeeded. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion-import +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success + resource: + name: network-external-deletion-import-external + description: Network from "external-deletion-import" test + adminStateUp: true + external: false + portSecurityEnabled: true + shared: false + status: ACTIVE diff --git a/internal/controllers/network/tests/network-external-deletion-import/01-import-resource.yaml b/internal/controllers/network/tests/network-external-deletion-import/01-import-resource.yaml new file mode 100644 index 000000000..a87f147bf --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/01-import-resource.yaml @@ -0,0 +1,19 @@ +--- +# Import the external network into ORC as an unmanaged resource. The import +# filter uses the unique description to identify the network created in step 00. +# A short resyncPeriod ensures ORC checks the network state periodically, so +# external deletion is detected without requiring a manual trigger. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + # resyncPeriod of 10s ensures ORC detects the external deletion quickly. + resyncPeriod: 10s + import: + filter: + description: Network from "external-deletion-import" test diff --git a/internal/controllers/network/tests/network-external-deletion-import/02-assert.yaml b/internal/controllers/network/tests/network-external-deletion-import/02-assert.yaml new file mode 100644 index 000000000..1a69ee107 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/02-assert.yaml @@ -0,0 +1,28 @@ +--- +# After the OpenStack network is deleted externally, ORC detects on the next +# reconcile (within the configured resyncPeriod of 10s) that the resource +# referenced by status.id no longer exists. +# +# Because the resource is unmanaged, ORC cannot recreate it. Instead it returns +# a terminal error, which sets both Progressing and Available to False with +# reason UnrecoverableError. +# +# The terminal error prevents any further reconciliation until the spec changes. +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 300 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion-import +status: + conditions: + - type: Available + message: resource has been deleted from OpenStack + status: "False" + reason: UnrecoverableError + - type: Progressing + message: resource has been deleted from OpenStack + status: "False" + reason: UnrecoverableError diff --git a/internal/controllers/network/tests/network-external-deletion-import/02-delete-from-openstack.yaml b/internal/controllers/network/tests/network-external-deletion-import/02-delete-from-openstack.yaml new file mode 100644 index 000000000..085a44867 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/02-delete-from-openstack.yaml @@ -0,0 +1,23 @@ +--- +# Delete the OpenStack network directly (bypassing ORC). We get the OpenStack +# ID from the unmanaged import's status.id and use the OpenStack CLI to remove +# the network without going through ORC. +# +# After this deletion, the unmanaged ORC object (network-external-deletion-import) +# still has status.id pointing to the now-deleted network. On the next reconcile +# (triggered by the resyncPeriod), ORC calls GetOSResourceByID and gets NotFound. +# Since the resource is unmanaged, ORC cannot recreate it and instead sets a +# terminal error (UnrecoverableError). +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: | + # Get the OpenStack ID referenced by the imported (unmanaged) ORC object. + NETWORK_ID=$(kubectl get network.openstack.k-orc.cloud network-external-deletion-import \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.id}') + + # Delete the network directly in OpenStack, bypassing ORC. + cd $(dirname ${E2E_KUTTL_OSCLOUDS}) + export OS_CLOUD=openstack + openstack network delete "${NETWORK_ID}" diff --git a/internal/controllers/network/tests/network-external-deletion-import/README.md b/internal/controllers/network/tests/network-external-deletion-import/README.md new file mode 100644 index 000000000..d0969093f --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion-import/README.md @@ -0,0 +1,27 @@ +# External deletion of an imported (unmanaged) Network produces a terminal error + +## Step 00 + +Create an external managed Network that will be used as the import target, +and wait for it to become available in OpenStack. + +## Step 01 + +Import the external network into ORC as an unmanaged resource (using an import +filter). Verify the import succeeds and the network is available. + +## Step 02 + +Delete the external OpenStack network directly (bypassing ORC). On the next +reconcile, ORC detects that the network referenced by `status.id` no longer +exists in OpenStack. Because the resource was originally imported (unmanaged), +ORC cannot recreate it - instead it sets a terminal error condition +(`UnrecoverableError`) with the message "resource has been deleted from +OpenStack". No further reconciliation occurs. + +## Reference + +Tests the external deletion handling for imported/unmanaged resources as +described in `resource_actions.go`: when a resource was originally imported +and is found to be missing from OpenStack, ORC returns a terminal error instead +of attempting recreation. diff --git a/internal/controllers/network/tests/network-external-deletion/00-assert.yaml b/internal/controllers/network/tests/network-external-deletion/00-assert.yaml new file mode 100644 index 000000000..01ad49f68 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion/00-assert.yaml @@ -0,0 +1,41 @@ +--- +# Verify the network is available and has a status.id set (OpenStack network ID). +# Record the original ID so we can compare after recreation in step 01. +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-external-deletion + ref: network +assertAll: + # Verify the OpenStack ID is set before we delete the network externally. + - celExpr: "network.status.id != ''" +commands: + - script: | + # Save the original OpenStack network ID for comparison in step 01. + kubectl get network.openstack.k-orc.cloud network-external-deletion \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.id}' \ + > /tmp/network-external-deletion-original-id +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success + resource: + name: network-external-deletion + description: Network from "external-deletion" test + adminStateUp: true + external: false + portSecurityEnabled: true + shared: false + status: ACTIVE diff --git a/internal/controllers/network/tests/network-external-deletion/00-create-resource.yaml b/internal/controllers/network/tests/network-external-deletion/00-create-resource.yaml new file mode 100644 index 000000000..95d4833ba --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion/00-create-resource.yaml @@ -0,0 +1,18 @@ +--- +# Create a managed Network resource and wait for ORC to create it in OpenStack. +# A short resyncPeriod ensures ORC checks the network state periodically, so +# external deletion is detected without requiring a manual trigger. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # resyncPeriod of 10s ensures ORC detects the external deletion quickly + # without requiring a watch event or manual trigger. + resyncPeriod: 10s + resource: + description: Network from "external-deletion" test diff --git a/internal/controllers/network/tests/network-external-deletion/00-secret.yaml b/internal/controllers/network/tests/network-external-deletion/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/network/tests/network-external-deletion/01-assert.yaml b/internal/controllers/network/tests/network-external-deletion/01-assert.yaml new file mode 100644 index 000000000..9d3712ea7 --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion/01-assert.yaml @@ -0,0 +1,50 @@ +--- +# After the OpenStack network is deleted externally, ORC detects the deletion +# via the configured resyncPeriod (10s). ORC clears status.id and recreates the +# network in OpenStack. Verify that: +# 1. The network is available again with correct conditions and resource status. +# 2. The OpenStack ID (status.id) has changed - a brand-new network was created. +# +# The timeout is set generously to allow for the resyncPeriod to elapse, the +# deletion to be detected, and the new network to be created and reach ACTIVE. +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 300 +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-external-deletion + ref: network +assertAll: + # The new OpenStack ID must be set and non-empty. + - celExpr: "network.status.id != ''" +commands: + - script: | + ORIGINAL=$(cat /tmp/network-external-deletion-original-id) + CURRENT=$(kubectl get network.openstack.k-orc.cloud network-external-deletion \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.id}') + # Succeed only when both IDs are set and the new ID differs from the original, + # confirming that ORC detected the external deletion and recreated the network. + [ -n "${ORIGINAL}" ] && [ -n "${CURRENT}" ] && [ "${CURRENT}" != "${ORIGINAL}" ] +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-external-deletion +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success + resource: + name: network-external-deletion + description: Network from "external-deletion" test + adminStateUp: true + external: false + portSecurityEnabled: true + shared: false + status: ACTIVE diff --git a/internal/controllers/network/tests/network-external-deletion/01-delete-from-openstack.yaml b/internal/controllers/network/tests/network-external-deletion/01-delete-from-openstack.yaml new file mode 100644 index 000000000..b932ef0ce --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion/01-delete-from-openstack.yaml @@ -0,0 +1,16 @@ +--- +# Delete the network directly in OpenStack, bypassing ORC. +# This simulates an external deletion event (e.g., an operator accidentally +# deleting the resource, or a garbage-collection script removing it). +# The resyncPeriod configured on the ORC object ensures ORC will detect +# the deletion within the configured period (10s) without needing a manual trigger. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: | + NETWORK_ID=$(cat /tmp/network-external-deletion-original-id) + + # Delete the network directly in OpenStack, bypassing ORC. + cd $(dirname ${E2E_KUTTL_OSCLOUDS}) + export OS_CLOUD=openstack + openstack network delete "${NETWORK_ID}" diff --git a/internal/controllers/network/tests/network-external-deletion/README.md b/internal/controllers/network/tests/network-external-deletion/README.md new file mode 100644 index 000000000..0ebe9310b --- /dev/null +++ b/internal/controllers/network/tests/network-external-deletion/README.md @@ -0,0 +1,29 @@ +# External deletion and recreation of a managed Network + +## Step 00 + +Create a managed Network resource with a short `resyncPeriod` (10s) and wait +for ORC to create it in OpenStack and report it as available. Record the +OpenStack network ID assigned by ORC. + +The `resyncPeriod` ensures ORC checks the network state periodically, allowing +it to detect external deletion without requiring a manual trigger or watch event. + +## Step 01 + +Delete the OpenStack network directly (bypassing ORC). ORC detects the deletion +on the next periodic resync (within 10s), clears `status.id`, and recreates +the network in OpenStack on the following reconcile. + +Verify that: +- The network is available again with correct conditions and resource status. +- The OpenStack ID in `status.id` has changed (a new network was created, + confirming ORC detected the external deletion and recreated the resource). + +## Reference + +Tests the external deletion handling for managed resources as described in +`internal/controllers/generic/reconciler/resource_actions.go`: when a managed, +non-imported resource is found to be missing from OpenStack (the ID in +`status.id` no longer exists), ORC clears `status.id` and recreates the +resource on the next reconcile. diff --git a/internal/controllers/network/tests/network-resync-disabled/00-assert.yaml b/internal/controllers/network/tests/network-resync-disabled/00-assert.yaml new file mode 100644 index 000000000..9b0edfd06 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-disabled/00-assert.yaml @@ -0,0 +1,33 @@ +--- +# Verify the network is available and lastSyncTime has been set after the +# initial reconciliation, even with resyncPeriod=0 (disabled periodic resync). +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-resync-disabled + ref: network +assertAll: + - celExpr: "has(network.status.lastSyncTime)" + - celExpr: "network.status.lastSyncTime != ''" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-disabled +status: + resource: + name: network-resync-disabled + adminStateUp: true + external: false + portSecurityEnabled: true + shared: false + status: ACTIVE + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/network/tests/network-resync-disabled/00-create-resource.yaml b/internal/controllers/network/tests/network-resync-disabled/00-create-resource.yaml new file mode 100644 index 000000000..3e1cf5fff --- /dev/null +++ b/internal/controllers/network/tests/network-resync-disabled/00-create-resource.yaml @@ -0,0 +1,13 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-disabled +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # resyncPeriod of 0s explicitly disables periodic resync. The controller + # should reconcile the resource once on creation and then not reschedule. + resyncPeriod: 0s + resource: {} diff --git a/internal/controllers/network/tests/network-resync-disabled/00-secret.yaml b/internal/controllers/network/tests/network-resync-disabled/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-disabled/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/network/tests/network-resync-disabled/01-assert.yaml b/internal/controllers/network/tests/network-resync-disabled/01-assert.yaml new file mode 100644 index 000000000..a645a3f05 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-disabled/01-assert.yaml @@ -0,0 +1,15 @@ +--- +# Verify the network is still available and stable after the waiting period. +# No changes should have occurred since no resync was triggered. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-disabled +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/network/tests/network-resync-disabled/01-check-no-resync.yaml b/internal/controllers/network/tests/network-resync-disabled/01-check-no-resync.yaml new file mode 100644 index 000000000..a74663299 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-disabled/01-check-no-resync.yaml @@ -0,0 +1,17 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +# Record the current lastSyncTime, sleep for 15 seconds (longer than even a +# fast resync period would trigger), then verify that lastSyncTime has NOT +# changed. This confirms that resyncPeriod=0 prevents periodic re-reconciliation. +commands: + - script: | + INITIAL=$(kubectl get network.openstack.k-orc.cloud network-resync-disabled \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.lastSyncTime}') + # Sleep longer than any reasonable minimum resync period to confirm no resync fires. + sleep 15 + CURRENT=$(kubectl get network.openstack.k-orc.cloud network-resync-disabled \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.lastSyncTime}') + # Fail if lastSyncTime changed (would indicate an unexpected resync). + [ "${INITIAL}" = "${CURRENT}" ] diff --git a/internal/controllers/network/tests/network-resync-disabled/README.md b/internal/controllers/network/tests/network-resync-disabled/README.md new file mode 100644 index 000000000..d97bfc2ff --- /dev/null +++ b/internal/controllers/network/tests/network-resync-disabled/README.md @@ -0,0 +1,21 @@ +# Network with resyncPeriod=0 disables periodic resync + +## Step 00 + +Create a network with `resyncPeriod: 0s` (disabled periodic resync) and verify that: +- The network becomes available with correct conditions. +- `lastSyncTime` is set in the status after the first successful reconciliation. + (Even with resync disabled, the controller always records the initial sync time.) + +## Step 01 + +Wait for a period longer than the minimum resync period and verify that +`lastSyncTime` has NOT changed. When `resyncPeriod` is 0 (disabled), the +controller does not schedule additional reconciliations, so `lastSyncTime` +should remain stable after the initial reconciliation. + +## Reference + +Tests that setting `resyncPeriod: 0s` (or omitting resyncPeriod) disables +periodic resync scheduling. The resource is still reconciled on events (spec +changes, dependency updates) but not on a timer. diff --git a/internal/controllers/network/tests/network-resync-jitter/00-assert.yaml b/internal/controllers/network/tests/network-resync-jitter/00-assert.yaml new file mode 100644 index 000000000..f19a692d1 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-jitter/00-assert.yaml @@ -0,0 +1,61 @@ +--- +# Verify all three networks are available and each has lastSyncTime set after +# the initial successful reconciliation. +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-resync-jitter-1 + ref: network1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-resync-jitter-2 + ref: network2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-resync-jitter-3 + ref: network3 +assertAll: + - celExpr: "has(network1.status.lastSyncTime) && network1.status.lastSyncTime != ''" + - celExpr: "has(network2.status.lastSyncTime) && network2.status.lastSyncTime != ''" + - celExpr: "has(network3.status.lastSyncTime) && network3.status.lastSyncTime != ''" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-jitter-1 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-jitter-2 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-jitter-3 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/network/tests/network-resync-jitter/00-create-resources.yaml b/internal/controllers/network/tests/network-resync-jitter/00-create-resources.yaml new file mode 100644 index 000000000..87bc8a883 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-jitter/00-create-resources.yaml @@ -0,0 +1,39 @@ +--- +# Create three networks all sharing the same resyncPeriod to exercise jitter +# scheduling. Each network will be independently scheduled with [0%, +20%] jitter, +# preventing them from all reconciling simultaneously. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-jitter-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resyncPeriod: 10s + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-jitter-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resyncPeriod: 10s + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-jitter-3 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resyncPeriod: 10s + resource: {} diff --git a/internal/controllers/network/tests/network-resync-jitter/00-secret.yaml b/internal/controllers/network/tests/network-resync-jitter/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-jitter/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/network/tests/network-resync-jitter/01-assert.yaml b/internal/controllers/network/tests/network-resync-jitter/01-assert.yaml new file mode 100644 index 000000000..86c345e3b --- /dev/null +++ b/internal/controllers/network/tests/network-resync-jitter/01-assert.yaml @@ -0,0 +1,39 @@ +--- +# After the resync period elapses, all three networks should have been +# independently re-reconciled. This assert waits for all three lastSyncTime +# values to advance beyond their recorded initial values and verifies that not +# all elapsed intervals are identical, confirming that jitter is observable in +# the end-to-end flow without requiring every random sample to be unique. +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 240 +commands: + - script: | + set -eu + + INIT1=$(cat /tmp/network-resync-jitter-1-initial-sync-time) + INIT2=$(cat /tmp/network-resync-jitter-2-initial-sync-time) + INIT3=$(cat /tmp/network-resync-jitter-3-initial-sync-time) + + CUR1=$(kubectl get network.openstack.k-orc.cloud network-resync-jitter-1 \ + -n ${NAMESPACE} -o jsonpath='{.status.lastSyncTime}') + CUR2=$(kubectl get network.openstack.k-orc.cloud network-resync-jitter-2 \ + -n ${NAMESPACE} -o jsonpath='{.status.lastSyncTime}') + CUR3=$(kubectl get network.openstack.k-orc.cloud network-resync-jitter-3 \ + -n ${NAMESPACE} -o jsonpath='{.status.lastSyncTime}') + + to_epoch_ns() { + date -u -d "$1" +%s%N + } + + DELTA1=$(( $(to_epoch_ns "${CUR1}") - $(to_epoch_ns "${INIT1}") )) + DELTA2=$(( $(to_epoch_ns "${CUR2}") - $(to_epoch_ns "${INIT2}") )) + DELTA3=$(( $(to_epoch_ns "${CUR3}") - $(to_epoch_ns "${INIT3}") )) + + # All three must update, and at least one observed interval must differ. + [ "${CUR1}" != "${INIT1}" ] && \ + [ "${CUR2}" != "${INIT2}" ] && \ + [ "${CUR3}" != "${INIT3}" ] && \ + { [ "${DELTA1}" -ne "${DELTA2}" ] || \ + [ "${DELTA1}" -ne "${DELTA3}" ] || \ + [ "${DELTA2}" -ne "${DELTA3}" ]; } diff --git a/internal/controllers/network/tests/network-resync-jitter/01-record-sync-times.yaml b/internal/controllers/network/tests/network-resync-jitter/01-record-sync-times.yaml new file mode 100644 index 000000000..9ff679a17 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-jitter/01-record-sync-times.yaml @@ -0,0 +1,18 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +# Record the current lastSyncTime for all three networks so that the following +# assert can detect when each network has been independently re-reconciled. +commands: + - script: | + kubectl get network.openstack.k-orc.cloud network-resync-jitter-1 \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.lastSyncTime}' \ + > /tmp/network-resync-jitter-1-initial-sync-time + kubectl get network.openstack.k-orc.cloud network-resync-jitter-2 \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.lastSyncTime}' \ + > /tmp/network-resync-jitter-2-initial-sync-time + kubectl get network.openstack.k-orc.cloud network-resync-jitter-3 \ + -n ${NAMESPACE} \ + -o jsonpath='{.status.lastSyncTime}' \ + > /tmp/network-resync-jitter-3-initial-sync-time diff --git a/internal/controllers/network/tests/network-resync-jitter/README.md b/internal/controllers/network/tests/network-resync-jitter/README.md new file mode 100644 index 000000000..240fa9d37 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-jitter/README.md @@ -0,0 +1,24 @@ +# Network resync with jitter + +## Step 00 + +Create three networks that all share the same `resyncPeriod` (10s). Once all +three become available, each will have a `lastSyncTime` that records when the +controller last successfully reconciled them. + +## Step 01 + +Record the initial `lastSyncTime` for all three networks. + +## Step 02 + +After the resync period elapses, verify that the three recorded timestamps have +advanced and that at least one elapsed interval differs. This confirms both +periodic resync and jittered scheduling for multiple resources using the same +period without requiring every random jitter sample to be unique. + +## Reference + +Tests periodic resync scheduling and jitter: resources with the same +`resyncPeriod` should be independently scheduled rather than all reconciling +simultaneously. diff --git a/internal/controllers/network/tests/network-resync-terminal-error/00-assert.yaml b/internal/controllers/network/tests/network-resync-terminal-error/00-assert.yaml new file mode 100644 index 000000000..3788843dd --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/00-assert.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-terminal-error-external-1 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-terminal-error-external-2 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/network/tests/network-resync-terminal-error/00-create-resources.yaml b/internal/controllers/network/tests/network-resync-terminal-error/00-create-resources.yaml new file mode 100644 index 000000000..76142252d --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/00-create-resources.yaml @@ -0,0 +1,26 @@ +--- +# Create two networks with the same description so that an import filter +# matching on that description will be ambiguous (multiple results). +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-terminal-error-external-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Network from "resync-terminal-error" test +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-terminal-error-external-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Network from "resync-terminal-error" test diff --git a/internal/controllers/network/tests/network-resync-terminal-error/00-secret.yaml b/internal/controllers/network/tests/network-resync-terminal-error/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/network/tests/network-resync-terminal-error/01-assert.yaml b/internal/controllers/network/tests/network-resync-terminal-error/01-assert.yaml new file mode 100644 index 000000000..c565120a1 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/01-assert.yaml @@ -0,0 +1,29 @@ +--- +# Verify the import fails with a terminal error (InvalidConfiguration) and +# that lastSyncTime is NOT set (no successful reconciliation occurred). +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-resync-terminal-error + ref: network +assertAll: + # lastSyncTime must NOT be set: the reconciliation never succeeded, so + # there is no time of last successful sync to record. + - celExpr: "!has(network.status.lastSyncTime)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-terminal-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/network/tests/network-resync-terminal-error/01-import-resource.yaml b/internal/controllers/network/tests/network-resync-terminal-error/01-import-resource.yaml new file mode 100644 index 000000000..e4f9360f7 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/01-import-resource.yaml @@ -0,0 +1,20 @@ +--- +# Attempt to import a network with a filter matching both external networks. +# This will result in a terminal error (InvalidConfiguration) because the +# filter is ambiguous. A resyncPeriod is set to verify that the terminal error +# prevents the resync scheduler from enqueuing further reconciliations. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-terminal-error +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + # resyncPeriod is configured so we can verify it is suppressed by the + # terminal error (the scheduler must not fire for a resource in this state). + resyncPeriod: 10s + import: + filter: + description: Network from "resync-terminal-error" test diff --git a/internal/controllers/network/tests/network-resync-terminal-error/02-assert.yaml b/internal/controllers/network/tests/network-resync-terminal-error/02-assert.yaml new file mode 100644 index 000000000..0fc02e90b --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/02-assert.yaml @@ -0,0 +1,29 @@ +--- +# After waiting longer than the configured resyncPeriod, the resource must +# still be in the terminal error state and lastSyncTime must still be absent. +# This confirms that the periodic resync scheduler correctly skips resources +# that have a terminal error. +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: network-resync-terminal-error + ref: network +assertAll: + - celExpr: "!has(network.status.lastSyncTime)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: network-resync-terminal-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/network/tests/network-resync-terminal-error/02-check-no-resync.yaml b/internal/controllers/network/tests/network-resync-terminal-error/02-check-no-resync.yaml new file mode 100644 index 000000000..d43838ba0 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/02-check-no-resync.yaml @@ -0,0 +1,9 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +# Wait for longer than the configured resyncPeriod (10s) to verify that the +# terminal error state prevents the resync scheduler from firing. +# If the scheduler incorrectly fires, the controller would reconcile again, +# potentially changing the condition message or setting lastSyncTime. +commands: + - script: | + sleep 15 diff --git a/internal/controllers/network/tests/network-resync-terminal-error/README.md b/internal/controllers/network/tests/network-resync-terminal-error/README.md new file mode 100644 index 000000000..990d9cb89 --- /dev/null +++ b/internal/controllers/network/tests/network-resync-terminal-error/README.md @@ -0,0 +1,30 @@ +# Terminal error resources don't resync + +## Step 00 + +Create two networks with identical descriptions so that an import filter +matching on that description will find multiple results. + +## Step 01 + +Attempt to import a network using a filter that matches both of the networks +created in step 00. This causes a terminal error (InvalidConfiguration) because +the import is ambiguous: the controller found more than one matching resource. + +Also configure `resyncPeriod: 10s` on the failing resource to verify that the +terminal error state prevents the resync scheduler from enqueuing additional +reconciliations. + +## Step 02 + +Wait 15 seconds (longer than the configured resyncPeriod) and verify that the +resource remains in the terminal error state. Specifically: +- Conditions still show InvalidConfiguration (terminal error unchanged). +- `lastSyncTime` is NOT set, because no successful reconciliation has occurred. +- The resource has NOT been re-reconciled (if resync fired, it might clear the + error or change the condition message). + +## Reference + +Tests that resources in a terminal error state are excluded from the periodic +resync scheduler. diff --git a/internal/controllers/network/zz_generated.adapter.go b/internal/controllers/network/zz_generated.adapter.go index 647cec323..59df47ad3 100644 --- a/internal/controllers/network/zz_generated.adapter.go +++ b/internal/controllers/network/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package network import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/network/zz_generated.controller.go b/internal/controllers/network/zz_generated.controller.go index e2b23d0d9..f054559f0 100644 --- a/internal/controllers/network/zz_generated.controller.go +++ b/internal/controllers/network/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/port/actuator.go b/internal/controllers/port/actuator.go index 570645623..0ff40ba21 100644 --- a/internal/controllers/port/actuator.go +++ b/internal/controllers/port/actuator.go @@ -25,9 +25,9 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsbinding" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsecurity" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portstrustedvif" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -37,6 +37,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" osclients "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" ) @@ -57,6 +58,45 @@ const ( serverBuildPollingPeriod = 15 * time.Second ) +// resolveHostID resolves the actual host ID string to use for port binding. +// It handles both direct ID specification and server reference. +// Returns the resolved host ID and a reconcile status (for waiting on dependencies). +func resolveHostID( + ctx context.Context, + k8sClient client.Client, + obj orcObjectPT, + hostIDSpec *orcv1alpha1.HostID, +) (string, progress.ReconcileStatus) { + if hostIDSpec == nil { + return "", nil + } + + // Direct ID specification + if hostIDSpec.ID != "" { + return hostIDSpec.ID, nil + } + + // Server reference - fetch the server and extract its hostID + if hostIDSpec.ServerRef != "" { + server, serverDepRS := dependency.FetchDependency( + ctx, k8sClient, obj.Namespace, &hostIDSpec.ServerRef, "Server", + func(dep *orcv1alpha1.Server) bool { + return orcv1alpha1.IsAvailable(dep) && + dep.Status.Resource != nil && + dep.Status.Resource.HostID != "" + }, + ) + if needsReschedule, _ := serverDepRS.NeedsReschedule(); needsReschedule { + return "", serverDepRS + } + if server != nil && server.Status.Resource != nil { + return server.Status.Resource.HostID, nil + } + } + + return "", nil +} + type portActuator struct { osClient osclients.NetworkClient k8sClient client.Client @@ -78,54 +118,61 @@ func (actuator portActuator) GetOSResourceByID(ctx context.Context, id string) ( } func (actuator portActuator) ListOSResourcesForAdoption(ctx context.Context, obj *orcv1alpha1.Port) (portIterator, bool) { - if obj.Spec.Resource == nil { + resource := obj.Spec.Resource + if resource == nil { + return nil, false + } + + // Resolve the network ID from NetworkRef. Without the network ID, + // adoption could match a port on the wrong network. + network, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, &resource.NetworkRef, "Network", + func(dep *orcv1alpha1.Network) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { return nil, false } - listOpts := ports.ListOpts{Name: getResourceName(obj)} + // Resolve the project ID from ProjectRef if set. + var projectID string + if resource.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + + listOpts := ports.ListOpts{ + Name: getResourceName(obj), + NetworkID: ptr.Deref(network.Status.ID, ""), + MACAddress: resource.MACAddress, + ProjectID: projectID, + } return actuator.osClient.ListPort(ctx, listOpts), true } func (actuator portActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { var reconcileStatus progress.ReconcileStatus - network := &orcv1alpha1.Network{} - if filter.NetworkRef != "" { - networkKey := client.ObjectKey{Name: string(filter.NetworkRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, networkKey, network); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Network", networkKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching network %s: %w", networkKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(network) || network.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Network", networkKey.Name, progress.WaitingOnReady)) - } - } - } + network, rs := dependency.FetchDependency[*orcv1alpha1.Network]( + ctx, actuator.k8sClient, obj.Namespace, &filter.NetworkRef, "Network", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) - project := &orcv1alpha1.Project{} - if filter.ProjectRef != nil { - projectKey := client.ObjectKey{Name: string(*filter.ProjectRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, projectKey, project); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching project %s: %w", projectKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(project) || project.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnReady)) - } - } - } + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -141,6 +188,7 @@ func (actuator portActuator) ListOSResourcesForImport(ctx context.Context, obj o NotTags: tags.Join(filter.NotTags), NotTagsAny: tags.Join(filter.NotTagsAny), AdminStateUp: filter.AdminStateUp, + MACAddress: filter.MACAddress, } return actuator.osClient.ListPort(ctx, listOpts), nil @@ -155,19 +203,13 @@ func (actuator portActuator) CreateResource(ctx context.Context, obj *orcv1alpha // Fetch all dependencies and ensure they have our finalizer network, networkDepRS := networkDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Network) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) subnetMap, subnetDepRS := subnetDependency.GetDependencies( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Subnet) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) secGroupMap, secGroupDepRS := securityGroupDependency.GetDependencies( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.SecurityGroup) bool { - return dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus := progress.NewReconcileStatus(). WithReconcileStatus(networkDepRS). @@ -177,9 +219,7 @@ func (actuator portActuator) CreateResource(ctx context.Context, obj *orcv1alpha var projectID string if resource.ProjectRef != nil { project, projectDepRS := projectDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Project) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) if project != nil { @@ -187,16 +227,36 @@ func (actuator portActuator) CreateResource(ctx context.Context, obj *orcv1alpha } } + // Resolve hostID if specified + var resolvedHostID string + if resource.HostID != nil { + var hostIDReconcileStatus progress.ReconcileStatus + resolvedHostID, hostIDReconcileStatus = resolveHostID(ctx, actuator.k8sClient, obj, resource.HostID) + reconcileStatus = reconcileStatus.WithReconcileStatus(hostIDReconcileStatus) + } + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus } + var valueSpecs *map[string]string + if len(resource.ValueSpecs) > 0 { + vs := make(map[string]string, len(resource.ValueSpecs)) + for _, valueSpec := range resource.ValueSpecs { + vs[valueSpec.Key] = *valueSpec.Value + } + valueSpecs = &vs + } + createOpts := ports.CreateOpts{ - NetworkID: *network.Status.ID, - Name: getResourceName(obj), - Description: string(ptr.Deref(resource.Description, "")), - ProjectID: projectID, - AdminStateUp: resource.AdminStateUp, + NetworkID: *network.Status.ID, + Name: getResourceName(obj), + Description: string(ptr.Deref(resource.Description, "")), + ProjectID: projectID, + AdminStateUp: resource.AdminStateUp, + MACAddress: resource.MACAddress, + ValueSpecs: valueSpecs, + PropagateUplinkStatus: resource.PropagateUplinkStatus, } if len(resource.AllowedAddressPairs) > 0 { @@ -252,6 +312,7 @@ func (actuator portActuator) CreateResource(ctx context.Context, obj *orcv1alpha portsBindingOpts := portsbinding.CreateOptsExt{ CreateOptsBuilder: createOpts, VNICType: resource.VNICType, + HostID: resolvedHostID, } portSecurityOpts := portsecurity.PortCreateOptsExt{ @@ -269,10 +330,17 @@ func (actuator portActuator) CreateResource(ctx context.Context, obj *orcv1alpha orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, fmt.Sprintf("Invalid value %s", resource.PortSecurity))) } - osResource, err := actuator.osClient.CreatePort(ctx, &portSecurityOpts) + portTrustedOpts := portstrustedvif.PortCreateOptsExt{ + CreateOptsBuilder: portSecurityOpts, + } + if resource.TrustedVIF != nil { + portTrustedOpts.PortTrustedVIF = resource.TrustedVIF + } + + osResource, err := actuator.osClient.CreatePort(ctx, &portTrustedOpts) if err != nil { - // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsConflict(err) { + // We should require the spec to be updated before retrying a create which returned a non-retryable error + if !orcerrors.IsRetryable(err) { err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) } return nil, progress.WrapError(err) @@ -341,9 +409,7 @@ func (actuator portActuator) updateResource(ctx context.Context, obj orcObjectPT } secGroupMap, secGroupDepRS := securityGroupDependency.GetDependencies( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.SecurityGroup) bool { - return dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus := progress.NewReconcileStatus(). @@ -369,6 +435,7 @@ func (actuator portActuator) updateResource(ctx context.Context, obj orcObjectPT updateOpts = handlePortBindingUpdate(updateOpts, resource, osResource) updateOpts = handlePortSecurityUpdate(updateOpts, resource, osResource) + updateOpts = handlePortTrustedVIFUpdate(updateOpts, resource, osResource) needsUpdate, err := needsUpdate(updateOpts) if err != nil { @@ -382,12 +449,10 @@ func (actuator portActuator) updateResource(ctx context.Context, obj orcObjectPT _, err = actuator.osClient.UpdatePort(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } @@ -441,7 +506,7 @@ func handleAllowedAddressPairsUpdate(updateOpts *ports.UpdateOpts, resource *orc for _, desired := range desiredPairs { found := false for _, actual := range osResource.AllowedAddressPairs { - if actual.IPAddress == desired.IPAddress && actual.MACAddress == desired.MACAddress { + if actual.IPAddress == desired.IPAddress && (desired.MACAddress == "" || actual.MACAddress == desired.MACAddress) { found = true break } @@ -456,7 +521,7 @@ func handleAllowedAddressPairsUpdate(updateOpts *ports.UpdateOpts, resource *orc for _, actual := range osResource.AllowedAddressPairs { found := false for _, desired := range desiredPairs { - if actual.IPAddress == desired.IPAddress && actual.MACAddress == desired.MACAddress { + if actual.IPAddress == desired.IPAddress && (desired.MACAddress == "" || actual.MACAddress == desired.MACAddress) { found = true break } @@ -502,6 +567,7 @@ func handlePortBindingUpdate(updateOpts ports.UpdateOptsBuilder, resource *resou } } } + return updateOpts } @@ -530,15 +596,29 @@ func handlePortSecurityUpdate(updateOpts ports.UpdateOptsBuilder, resource *reso return updateOpts } -func handleAdminStateUpUpdate(updateOpts *ports.UpdateOpts, resource *resourceSpecT, osResouce *osResourceT) { +func handleAdminStateUpUpdate(updateOpts *ports.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { adminStateUp := resource.AdminStateUp if adminStateUp != nil { - if *adminStateUp != osResouce.AdminStateUp { + if *adminStateUp != osResource.AdminStateUp { updateOpts.AdminStateUp = adminStateUp } } } +func handlePortTrustedVIFUpdate(updateOpts ports.UpdateOptsBuilder, resource *resourceSpecT, osResource *osResourceT) ports.UpdateOptsBuilder { + trusted := resource.TrustedVIF + if trusted != nil { + if osResource.PortTrustedVIF == nil || *trusted != *osResource.PortTrustedVIF { + updateOpts = portstrustedvif.PortUpdateOptsExt{ + UpdateOptsBuilder: updateOpts, + PortTrustedVIF: trusted, + } + } + } + + return updateOpts +} + type portHelperFactory struct{} var _ helperFactory = portHelperFactory{} diff --git a/internal/controllers/port/actuator_test.go b/internal/controllers/port/actuator_test.go index 81a2a7cc6..4f9a5adc7 100644 --- a/internal/controllers/port/actuator_test.go +++ b/internal/controllers/port/actuator_test.go @@ -5,6 +5,7 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsbinding" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsecurity" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portstrustedvif" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports" orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" osclients "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" @@ -205,6 +206,28 @@ func TestHandleAllowedAddressPairsUpdate(t *testing.T) { }, expectChange: true, }, + { + name: "Entry with empty MAC address", + newValue: []orcv1alpha1.AllowedAddressPair{ + {IP: orcv1alpha1.IPvAny("192.168.100.1")}, + }, + existingValue: []ports.AddressPair{ + {IPAddress: "192.168.100.1", MACAddress: "00:1A:2B:3C:4D:5E"}, + }, + expectChange: false, + }, + { + name: "Entries with empty and filled MAC addresses", + newValue: []orcv1alpha1.AllowedAddressPair{ + {IP: orcv1alpha1.IPvAny("192.168.100.1")}, + {IP: orcv1alpha1.IPvAny("192.168.200.1"), MAC: ptr.To(orcv1alpha1.MAC("00:1A:2B:3C:4D:6E"))}, + }, + existingValue: []ports.AddressPair{ + {IPAddress: "192.168.100.1", MACAddress: "00:1A:2B:3C:4D:5E"}, + {IPAddress: "192.168.200.1", MACAddress: "00:1A:2B:3C:4D:6E"}, + }, + expectChange: false, + }, } for _, tt := range testCases { @@ -234,8 +257,8 @@ func makeSecGroupWithID(id string) *orcv1alpha1.SecurityGroup { } func TestHandleSecurityGroupRefsUpdate(t *testing.T) { - sgWebName := orcv1alpha1.OpenStackName("sg-web") - sgDbName := orcv1alpha1.OpenStackName("sg-db") + sgWebName := orcv1alpha1.KubernetesNameRef("sg-web") + sgDbName := orcv1alpha1.KubernetesNameRef("sg-db") idWeb := "d564a44b-346c-4f71-92b1-5899b8979374" idDb := "1d23d83b-2a78-4c12-9e55-0a6e026dd201" @@ -243,14 +266,14 @@ func TestHandleSecurityGroupRefsUpdate(t *testing.T) { testCases := []struct { name string - newValue []orcv1alpha1.OpenStackName + newValue []orcv1alpha1.KubernetesNameRef existingValue []string secGroupMap map[string]*orcv1alpha1.SecurityGroup expectChange bool }{ { name: "Identical", - newValue: []orcv1alpha1.OpenStackName{sgWebName, sgDbName}, + newValue: []orcv1alpha1.KubernetesNameRef{sgWebName, sgDbName}, existingValue: []string{idWeb, idDb}, secGroupMap: map[string]*orcv1alpha1.SecurityGroup{ string(sgWebName): makeSecGroupWithID(idWeb), @@ -260,7 +283,7 @@ func TestHandleSecurityGroupRefsUpdate(t *testing.T) { }, { name: "Identical but different order", - newValue: []orcv1alpha1.OpenStackName{sgDbName, sgWebName}, + newValue: []orcv1alpha1.KubernetesNameRef{sgDbName, sgWebName}, existingValue: []string{idWeb, idDb}, secGroupMap: map[string]*orcv1alpha1.SecurityGroup{ string(sgWebName): makeSecGroupWithID(idWeb), @@ -270,7 +293,7 @@ func TestHandleSecurityGroupRefsUpdate(t *testing.T) { }, { name: "Add a security group", - newValue: []orcv1alpha1.OpenStackName{sgWebName, sgDbName}, + newValue: []orcv1alpha1.KubernetesNameRef{sgWebName, sgDbName}, existingValue: []string{idWeb}, secGroupMap: map[string]*orcv1alpha1.SecurityGroup{ string(sgWebName): makeSecGroupWithID(idWeb), @@ -280,7 +303,7 @@ func TestHandleSecurityGroupRefsUpdate(t *testing.T) { }, { name: "Remove a security group", - newValue: []orcv1alpha1.OpenStackName{sgWebName}, + newValue: []orcv1alpha1.KubernetesNameRef{sgWebName}, existingValue: []string{idWeb, idDb}, secGroupMap: map[string]*orcv1alpha1.SecurityGroup{ string(sgWebName): makeSecGroupWithID(idWeb), @@ -290,7 +313,7 @@ func TestHandleSecurityGroupRefsUpdate(t *testing.T) { }, { name: "Replace a security group", - newValue: []orcv1alpha1.OpenStackName{sgWebName, sgDbName}, + newValue: []orcv1alpha1.KubernetesNameRef{sgWebName, sgDbName}, existingValue: []string{idWeb, idOther}, secGroupMap: map[string]*orcv1alpha1.SecurityGroup{ string(sgWebName): makeSecGroupWithID(idWeb), @@ -300,14 +323,14 @@ func TestHandleSecurityGroupRefsUpdate(t *testing.T) { }, { name: "Remove all security groups", - newValue: []orcv1alpha1.OpenStackName{}, + newValue: []orcv1alpha1.KubernetesNameRef{}, existingValue: []string{idWeb, idDb}, secGroupMap: map[string]*orcv1alpha1.SecurityGroup{}, expectChange: true, }, { name: "Add to empty list", - newValue: []orcv1alpha1.OpenStackName{sgWebName}, + newValue: []orcv1alpha1.KubernetesNameRef{sgWebName}, existingValue: []string{}, secGroupMap: map[string]*orcv1alpha1.SecurityGroup{ string(sgWebName): makeSecGroupWithID(idWeb), @@ -435,3 +458,36 @@ func TestHandleAdminStateUpUpdate(t *testing.T) { }) } } + +func TestHandleTrustedVIFUpdate(t *testing.T) { + testCases := []struct { + name string + newValue *bool + existingValue *bool + expectChange bool + }{ + {name: "Enabled when the value is not set", newValue: ptr.To(true), existingValue: nil, expectChange: true}, + {name: "Enabled when was disabled", newValue: ptr.To(true), existingValue: ptr.To(false), expectChange: true}, + {name: "Disabled when was enabled", newValue: ptr.To(false), existingValue: ptr.To(true), expectChange: true}, + {name: "Keep the existing value if newValue is not set", newValue: nil, existingValue: ptr.To(true), expectChange: false}, + {name: "Keep the existing value when they are the same (true)", newValue: ptr.To(true), existingValue: ptr.To(true), expectChange: false}, + {name: "Keep the existing value when they are the same (false)", newValue: ptr.To(false), existingValue: ptr.To(false), expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.PortResourceSpec{TrustedVIF: tt.newValue} + osResource := &osclients.PortExt{ + PortTrustedVIFExt: portstrustedvif.PortTrustedVIFExt{ + PortTrustedVIF: tt.existingValue, + }, + } + + updateOpts := handlePortTrustedVIFUpdate(&ports.UpdateOpts{}, resource, osResource) + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("expected needsUpdate=%v, got %v", tt.expectChange, got) + } + }) + } +} diff --git a/internal/controllers/port/controller.go b/internal/controllers/port/controller.go index 6191d84b3..5da5ca1d1 100644 --- a/internal/controllers/port/controller.go +++ b/internal/controllers/port/controller.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -127,6 +128,17 @@ var ( return []string{string(*resource.Filter.ProjectRef)} }, ) + + serverDependency = dependency.NewDependency[*orcv1alpha1.PortList, *orcv1alpha1.Server]( + "spec.resource.hostID.serverRef", + func(port *orcv1alpha1.Port) []string { + resource := port.Spec.Resource + if resource == nil || resource.HostID == nil || resource.HostID.ServerRef == "" { + return nil + } + return []string{string(resource.HostID.ServerRef)} + }, + ) ) // serverToPortMapFunc creates a mapping function that reconciles ports when: @@ -197,6 +209,12 @@ func serverToPortMapFunc(ctx context.Context, k8sClient client.Client) handler.M log.V(logging.Verbose).Info("port needs reconciliation: listed in server status but deviceID not set", "port", client.ObjectKeyFromObject(port), "server", client.ObjectKeyFromObject(server)) + } else if portStatus.Status == PortStatusDown { + shouldReconcile = true + reason = "Port attached to server but status is still DOWN" + log.V(logging.Verbose).Info("port needs reconciliation: attached to server but status is DOWN", + "port", client.ObjectKeyFromObject(port), + "server", client.ObjectKeyFromObject(server)) } } @@ -245,19 +263,24 @@ func serverToPortMapFunc(ctx context.Context, k8sClient client.Client) handler.M } type portReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return portReconcilerConstructor{scopeFactory: scopeFactory} + return &portReconcilerConstructor{scopeFactory: scopeFactory} } func (portReconcilerConstructor) GetName() string { return controllerName } +func (c *portReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c portReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *portReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := mgr.GetLogger().WithValues("controller", controllerName) k8sClient := mgr.GetClient() @@ -291,6 +314,11 @@ func (c portReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctr return err } + serverWatchEventHandler, err := serverDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + builder := ctrl.NewControllerManagedBy(mgr). WithOptions(options). For(&orcv1alpha1.Port{}). @@ -314,6 +342,9 @@ func (c portReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctr Watches(&orcv1alpha1.Project{}, projectImportWatchEventHandler, builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), ). + Watches(&orcv1alpha1.Server{}, serverWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Server{})), + ). Watches(&orcv1alpha1.Server{}, handler.EnqueueRequestsFromMapFunc(serverToPortMapFunc(ctx, k8sClient)), builder.WithPredicates(predicates.NewServerInterfacesChanged(log)), ) @@ -325,12 +356,13 @@ func (c portReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctr securityGroupDependency.AddToManager(ctx, mgr), projectDependency.AddToManager(ctx, mgr), projectImportDependency.AddToManager(ctx, mgr), + serverDependency.AddToManager(ctx, mgr), credentialsDependency.AddToManager(ctx, mgr), credentials.AddCredentialsWatch(log, k8sClient, builder, credentialsDependency), ); err != nil { return err } - r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, portHelperFactory{}, portStatusWriter{}) + r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, portHelperFactory{}, portStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/port/status.go b/internal/controllers/port/status.go index d740caac0..f7e466971 100644 --- a/internal/controllers/port/status.go +++ b/internal/controllers/port/status.go @@ -67,13 +67,12 @@ func (portStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResou WithNetworkID(osResource.NetworkID). WithTags(osResource.Tags...). WithSecurityGroups(osResource.SecurityGroups...). - WithPropagateUplinkStatus(osResource.PropagateUplinkStatus). WithVNICType(osResource.VNICType). WithPortSecurityEnabled(osResource.PortSecurityEnabled). WithRevisionNumber(int64(osResource.RevisionNumber)). WithCreatedAt(metav1.NewTime(osResource.CreatedAt)). WithUpdatedAt(metav1.NewTime(osResource.UpdatedAt)). - WithAdminStateUp(osResource.AdminStateUp) + WithHostID(osResource.HostID) if osResource.Description != "" { resourceStatus.WithDescription(osResource.Description) @@ -104,5 +103,13 @@ func (portStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResou resourceStatus.WithFixedIPs(fixedIPs...) } + if osResource.PortTrustedVIF != nil { + resourceStatus.WithTrustedVIF(*osResource.PortTrustedVIF) + } + + if osResource.PropagateUplinkStatusPtr != nil { + resourceStatus.WithPropagateUplinkStatus(*osResource.PropagateUplinkStatusPtr) + } + statusApply.WithResource(resourceStatus) } diff --git a/internal/controllers/port/tests/port-create-full/00-assert.yaml b/internal/controllers/port/tests/port-create-full/00-assert.yaml index 3f2ea0750..f4ae02435 100644 --- a/internal/controllers/port/tests/port-create-full/00-assert.yaml +++ b/internal/controllers/port/tests/port-create-full/00-assert.yaml @@ -14,7 +14,9 @@ status: portSecurityEnabled: true propagateUplinkStatus: false status: DOWN - vnicType: direct + vnicType: macvtap + macAddress: fa:16:3e:23:fd:d7 + hostID: devstack tags: - tag1 --- @@ -28,11 +30,11 @@ resourceRefs: - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: subnet name: port-create-full - ref: subnet + ref: subnet - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: securitygroup name: port-create-full - ref: sg + ref: sg - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: project name: port-create-full @@ -41,7 +43,6 @@ assertAll: - celExpr: "port.status.id != ''" - celExpr: "port.status.resource.createdAt != ''" - celExpr: "port.status.resource.updatedAt != ''" - - celExpr: "port.status.resource.macAddress != ''" - celExpr: "port.status.resource.revisionNumber > 0" - celExpr: "port.status.resource.fixedIPs[0].subnetID == subnet.status.id" - celExpr: "port.status.resource.fixedIPs[0].ip == '192.168.155.122'" diff --git a/internal/controllers/port/tests/port-create-full/00-create-resource.yaml b/internal/controllers/port/tests/port-create-full/00-create-resource.yaml index 31174591f..53ca4413b 100644 --- a/internal/controllers/port/tests/port-create-full/00-create-resource.yaml +++ b/internal/controllers/port/tests/port-create-full/00-create-resource.yaml @@ -82,5 +82,9 @@ spec: - subnetRef: port-create-full ip: 192.168.155.122 portSecurity: Enabled - vnicType: direct + vnicType: macvtap projectRef: port-create-full + macAddress: fa:16:3e:23:fd:d7 + hostID: + id: devstack + propagateUplinkStatus: false diff --git a/internal/controllers/port/tests/port-create-full/README.md b/internal/controllers/port/tests/port-create-full/README.md index b59db2e92..39fdd3351 100644 --- a/internal/controllers/port/tests/port-create-full/README.md +++ b/internal/controllers/port/tests/port-create-full/README.md @@ -4,6 +4,11 @@ Create a port using all available fields, and verify that the observed state corresponds to the spec. +We're omitting the `ValueSpecs` field on purpose because we can't +reliably test it, since the key-value pairs in this structure depend +solely on the underlying OpenStack implementation, and thus the added +fields are unpredictable. + Also validate that the OpenStack resource uses the name from the spec when it is specified. ## Reference diff --git a/internal/controllers/port/tests/port-create-minimal/00-assert.yaml b/internal/controllers/port/tests/port-create-minimal/00-assert.yaml index 9c6d861fc..ba68844fe 100644 --- a/internal/controllers/port/tests/port-create-minimal/00-assert.yaml +++ b/internal/controllers/port/tests/port-create-minimal/00-assert.yaml @@ -8,7 +8,7 @@ status: name: port-create-minimal adminStateUp: true portSecurityEnabled: true - propagateUplinkStatus: false + propagateUplinkStatus: true revisionNumber: 1 status: DOWN vnicType: normal diff --git a/internal/controllers/port/tests/port-create-sriov/00-assert.yaml b/internal/controllers/port/tests/port-create-sriov/00-assert.yaml index 3277dfaea..f5f0205c8 100644 --- a/internal/controllers/port/tests/port-create-sriov/00-assert.yaml +++ b/internal/controllers/port/tests/port-create-sriov/00-assert.yaml @@ -9,23 +9,32 @@ status: description: Port from "create sriov" test adminStateUp: true portSecurityEnabled: false - propagateUplinkStatus: false + propagateUplinkStatus: true status: DOWN vnicType: direct tags: - tag1 --- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: port-create-sriov-admin +status: + resource: + name: port-create-sriov-admin + trustedVIF: true +--- apiVersion: kuttl.dev/v1beta1 kind: TestAssert resourceRefs: - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: port name: port-create-sriov - ref: port + ref: port - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: subnet name: port-create-sriov - ref: subnet + ref: subnet assertAll: - celExpr: "port.status.id != ''" - celExpr: "port.status.resource.createdAt != ''" @@ -35,4 +44,4 @@ assertAll: - celExpr: "port.status.resource.fixedIPs[0].subnetID == subnet.status.id" - celExpr: "port.status.resource.fixedIPs[0].ip == '192.168.155.122'" - celExpr: "!has(port.status.resource.allowedAddressPairs)" - - celExpr: "!has(port.status.resource.securityGroups)" \ No newline at end of file + - celExpr: "!has(port.status.resource.securityGroups)" diff --git a/internal/controllers/port/tests/port-create-sriov/00-create-resource.yaml b/internal/controllers/port/tests/port-create-sriov/00-create-resource.yaml index 69e968816..3318f0ce8 100644 --- a/internal/controllers/port/tests/port-create-sriov/00-create-resource.yaml +++ b/internal/controllers/port/tests/port-create-sriov/00-create-resource.yaml @@ -43,4 +43,19 @@ spec: addresses: - subnetRef: port-create-sriov ip: 192.168.155.122 - vnicType: direct \ No newline at end of file + vnicType: direct +--- +# This port is intended to be used to update fields where policies +# enforce its mutability only by admins. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: port-create-sriov-admin +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: port-create-sriov + trustedVIF: true diff --git a/internal/controllers/port/tests/port-create-sriov/README.md b/internal/controllers/port/tests/port-create-sriov/README.md index 492044bb6..05d6e4d0a 100644 --- a/internal/controllers/port/tests/port-create-sriov/README.md +++ b/internal/controllers/port/tests/port-create-sriov/README.md @@ -2,7 +2,7 @@ ## Step 00 -Create a port with vnic type direct and port security disabled, and verify that the observed state corresponds to the spec. +Create two ports: one with vnic type direct and port security disabled, and another with admin credentials, so that we can use fields which are enforced by policies, and verify that the observed state corresponds to the spec. Also validate that the OpenStack resource uses the name from the spec when it is specified. diff --git a/internal/controllers/port/tests/port-import/00-import-resource.yaml b/internal/controllers/port/tests/port-import/00-import-resource.yaml index bed7543ba..0b58377dc 100644 --- a/internal/controllers/port/tests/port-import/00-import-resource.yaml +++ b/internal/controllers/port/tests/port-import/00-import-resource.yaml @@ -13,5 +13,6 @@ spec: name: port-import-external description: Port from "port-import" test adminStateUp: false + macAddress: fa:16:3e:23:fd:d7 tags: - tag1 diff --git a/internal/controllers/port/tests/port-import/02-assert.yaml b/internal/controllers/port/tests/port-import/02-assert.yaml index ff0745560..3ef560d86 100644 --- a/internal/controllers/port/tests/port-import/02-assert.yaml +++ b/internal/controllers/port/tests/port-import/02-assert.yaml @@ -31,5 +31,6 @@ status: name: port-import-external description: Port from "port-import" test adminStateUp: false + macAddress: fa:16:3e:23:fd:d7 tags: - tag1 diff --git a/internal/controllers/port/tests/port-import/02-create-resource.yaml b/internal/controllers/port/tests/port-import/02-create-resource.yaml index 838d1d0d6..bbd3842bb 100644 --- a/internal/controllers/port/tests/port-import/02-create-resource.yaml +++ b/internal/controllers/port/tests/port-import/02-create-resource.yaml @@ -12,5 +12,6 @@ spec: networkRef: port-import description: Port from "port-import" test adminStateUp: false + macAddress: fa:16:3e:23:fd:d7 tags: - tag1 diff --git a/internal/controllers/port/tests/port-update/00-assert.yaml b/internal/controllers/port/tests/port-update/00-assert.yaml index fef380932..69cdc99e8 100644 --- a/internal/controllers/port/tests/port-update/00-assert.yaml +++ b/internal/controllers/port/tests/port-update/00-assert.yaml @@ -2,17 +2,17 @@ apiVersion: kuttl.dev/v1beta1 kind: TestAssert resourceRefs: - - apiVersion: openstack.k-orc.cloud/v1alpha1 - kind: port - name: port-update - ref: port + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: port + name: port-update + ref: port assertAll: - - celExpr: "port.status.id != ''" - - celExpr: "port.status.resource.createdAt != ''" - - celExpr: "port.status.resource.updatedAt != ''" - - celExpr: "port.status.resource.macAddress != ''" - - celExpr: "!has(port.status.resource.fixedIPs)" - - celExpr: "!has(port.status.resource.description)" + - celExpr: "port.status.id != ''" + - celExpr: "port.status.resource.createdAt != ''" + - celExpr: "port.status.resource.updatedAt != ''" + - celExpr: "port.status.resource.macAddress != ''" + - celExpr: "!has(port.status.resource.fixedIPs)" + - celExpr: "!has(port.status.resource.description)" --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Port @@ -23,7 +23,7 @@ status: name: port-update adminStateUp: true portSecurityEnabled: false - propagateUplinkStatus: false + propagateUplinkStatus: true revisionNumber: 1 status: DOWN vnicType: normal @@ -36,3 +36,22 @@ status: message: OpenStack resource is up to date status: "False" reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: port-update-admin +status: + resource: + name: port-update-admin + revisionNumber: 1 + trustedVIF: true + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/port/tests/port-update/00-minimal-resource.yaml b/internal/controllers/port/tests/port-update/00-minimal-resource.yaml index d1242e77f..3a1d6d2e9 100644 --- a/internal/controllers/port/tests/port-update/00-minimal-resource.yaml +++ b/internal/controllers/port/tests/port-update/00-minimal-resource.yaml @@ -12,3 +12,18 @@ spec: portSecurity: Disabled # Need to set the default values to revert them correctly in the 02-revert-resource step. vnicType: normal +--- +# This port is intended to be used to update fields where policies +# enforce its mutability only by admins. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: port-update-admin +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: port-update + trustedVIF: true diff --git a/internal/controllers/port/tests/port-update/00-prerequisites.yaml b/internal/controllers/port/tests/port-update/00-prerequisites.yaml index def6c7a09..ee6959c8b 100644 --- a/internal/controllers/port/tests/port-update/00-prerequisites.yaml +++ b/internal/controllers/port/tests/port-update/00-prerequisites.yaml @@ -40,4 +40,4 @@ spec: cloudName: openstack secretName: openstack-clouds resource: - name: port-update \ No newline at end of file + name: port-update diff --git a/internal/controllers/port/tests/port-update/01-assert.yaml b/internal/controllers/port/tests/port-update/01-assert.yaml index ef7850e61..0fa512121 100644 --- a/internal/controllers/port/tests/port-update/01-assert.yaml +++ b/internal/controllers/port/tests/port-update/01-assert.yaml @@ -34,7 +34,7 @@ status: description: port-update-updated adminStateUp: true portSecurityEnabled: true - propagateUplinkStatus: false + propagateUplinkStatus: true status: DOWN vnicType: direct allowedAddressPairs: @@ -48,4 +48,22 @@ status: reason: Success - type: Progressing status: "False" - reason: Success \ No newline at end of file + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: port-update-admin +status: + resource: + name: port-update-admin + trustedVIF: false + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/port/tests/port-update/01-updated-resource.yaml b/internal/controllers/port/tests/port-update/01-updated-resource.yaml index 796726336..b86771ba2 100644 --- a/internal/controllers/port/tests/port-update/01-updated-resource.yaml +++ b/internal/controllers/port/tests/port-update/01-updated-resource.yaml @@ -19,4 +19,16 @@ spec: tags: - tag1 vnicType: direct - portSecurity: Enabled \ No newline at end of file + portSecurity: Enabled +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: port-update-admin +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + trustedVIF: false diff --git a/internal/controllers/port/tests/port-update/02-assert.yaml b/internal/controllers/port/tests/port-update/02-assert.yaml index 314caa5b0..a96e5d05a 100644 --- a/internal/controllers/port/tests/port-update/02-assert.yaml +++ b/internal/controllers/port/tests/port-update/02-assert.yaml @@ -24,7 +24,7 @@ status: name: port-update adminStateUp: true portSecurityEnabled: false - propagateUplinkStatus: false + propagateUplinkStatus: true status: DOWN vnicType: normal conditions: @@ -35,4 +35,22 @@ status: - type: Progressing message: OpenStack resource is up to date status: "False" - reason: Success \ No newline at end of file + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: port-update-admin +status: + resource: + name: port-update-admin + trustedVIF: true + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/port/tests/port-update/02-reverted-resource.yaml b/internal/controllers/port/tests/port-update/02-reverted-resource.yaml index ec043aae6..2c6c253ff 100644 --- a/internal/controllers/port/tests/port-update/02-reverted-resource.yaml +++ b/internal/controllers/port/tests/port-update/02-reverted-resource.yaml @@ -4,4 +4,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - command: kubectl replace -f 00-minimal-resource.yaml - namespaced: true \ No newline at end of file + namespaced: true diff --git a/internal/controllers/port/zz_generated.adapter.go b/internal/controllers/port/zz_generated.adapter.go index e9ca55c79..4862fbb04 100644 --- a/internal/controllers/port/zz_generated.adapter.go +++ b/internal/controllers/port/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package port import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/port/zz_generated.controller.go b/internal/controllers/port/zz_generated.controller.go index 290986682..160f732dc 100644 --- a/internal/controllers/port/zz_generated.controller.go +++ b/internal/controllers/port/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/project/actuator.go b/internal/controllers/project/actuator.go index 2b882ae91..1ea580e8c 100644 --- a/internal/controllers/project/actuator.go +++ b/internal/controllers/project/actuator.go @@ -25,11 +25,13 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" generic "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" ) @@ -53,7 +55,8 @@ type projectClient interface { } type projectActuator struct { - osClient projectClient + osClient projectClient + k8sClient client.Client } var _ createResourceActuator = projectActuator{} @@ -72,21 +75,52 @@ func (actuator projectActuator) GetOSResourceByID(ctx context.Context, id string } func (actuator projectActuator) ListOSResourcesForAdoption(ctx context.Context, obj orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { - if obj.Spec.Resource == nil { + resource := obj.Spec.Resource + if resource == nil { return nil, false } + // Resolve the domain ID from DomainRef if set. Without the domain + // ID, adoption could match a project in the wrong domain. + var domainID string + if resource.DomainRef != nil { + domain, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.DomainRef, "Domain", + func(dep *orcv1alpha1.Domain) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + domainID = ptr.Deref(domain.Status.ID, "") + } + listOpts := projects.ListOpts{ - Name: getResourceName(obj), - Tags: tags.Join(obj.Spec.Resource.Tags), + Name: getResourceName(obj), + DomainID: domainID, + Tags: tags.Join(resource.Tags), } return actuator.osClient.ListProjects(ctx, listOpts), true } func (actuator projectActuator) ListOSResourcesForImport(ctx context.Context, orcObject orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + domain, rs := dependency.FetchDependency[*orcv1alpha1.Domain]( + ctx, actuator.k8sClient, orcObject.Namespace, filter.DomainRef, "Domain", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + listOpts := projects.ListOpts{ Name: string(ptr.Deref(filter.Name, "")), + DomainID: ptr.Deref(domain.Status.ID, ""), Tags: tags.Join(filter.Tags), TagsAny: tags.Join(filter.TagsAny), NotTags: tags.Join(filter.NotTags), @@ -104,6 +138,21 @@ func (actuator projectActuator) CreateResource(ctx context.Context, obj orcObjec return nil, progress.WrapError( orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) } + var reconcileStatus progress.ReconcileStatus + + var domainID string + if resource.DomainRef != nil { + domain, domainDepRS := domainDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(domainDepRS) + if domain != nil { + domainID = ptr.Deref(domain.Status.ID, "") + } + } + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } tags := make([]string, len(resource.Tags)) for i := range resource.Tags { @@ -115,6 +164,7 @@ func (actuator projectActuator) CreateResource(ctx context.Context, obj orcObjec createOpts := projects.CreateOpts{ Name: getResourceName(obj), Description: ptr.Deref(resource.Description, ""), + DomainID: domainID, Enabled: resource.Enabled, Tags: tags, } @@ -168,8 +218,11 @@ func (actuator projectActuator) updateResource(ctx context.Context, obj orcObjec _, err = actuator.osClient.UpdateProject(ctx, osResource.ID, updateOpts) - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) } if err != nil { return progress.WrapError(err) @@ -251,7 +304,8 @@ func newActuator(ctx context.Context, orcObject *orcv1alpha1.Project, controller } return projectActuator{ - osClient: osClient, + osClient: osClient, + k8sClient: controller.GetK8sClient(), }, nil } diff --git a/internal/controllers/project/controller.go b/internal/controllers/project/controller.go index 8112555ae..74dddc532 100644 --- a/internal/controllers/project/controller.go +++ b/internal/controllers/project/controller.go @@ -19,8 +19,10 @@ package project import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/controller" orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" @@ -29,6 +31,8 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" "github.com/k-orc/openstack-resource-controller/v2/internal/scope" "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" ) const controllerName = "project" @@ -37,32 +41,80 @@ const controllerName = "project" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=projects/status,verbs=get;update;patch type projectReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return projectReconcilerConstructor{scopeFactory: scopeFactory} + return &projectReconcilerConstructor{scopeFactory: scopeFactory} } func (projectReconcilerConstructor) GetName() string { return controllerName } +func (c *projectReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var domainDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ProjectList, *orcv1alpha1.Domain]( + "spec.resource.domainRef", + func(project *orcv1alpha1.Project) []string { + resource := project.Spec.Resource + if resource == nil || resource.DomainRef == nil { + return nil + } + return []string{string(*resource.DomainRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var domainImportDependency = dependency.NewDependency[*orcv1alpha1.ProjectList, *orcv1alpha1.Domain]( + "spec.import.filter.domainRef", + func(project *orcv1alpha1.Project) []string { + resource := project.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.DomainRef == nil { + return nil + } + return []string{string(*resource.Filter.DomainRef)} + }, +) + // SetupWithManager sets up the controller with the Manager. -func (c projectReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *projectReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + domainWatchEventHandler, err := domainDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + domainImportWatchEventHandler, err := domainImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } builder := ctrl.NewControllerManagedBy(mgr). WithOptions(options). + Watches(&orcv1alpha1.Domain{}, domainWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Domain{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Domain{}, domainImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Domain{})), + ). For(&orcv1alpha1.Project{}) if err := errors.Join( + domainDependency.AddToManager(ctx, mgr), + domainImportDependency.AddToManager(ctx, mgr), credentialsDependency.AddToManager(ctx, mgr), credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), ); err != nil { return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, projectHelperFactory{}, projectStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, projectHelperFactory{}, projectStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/project/status.go b/internal/controllers/project/status.go index 15ed56656..9ff6ef10c 100644 --- a/internal/controllers/project/status.go +++ b/internal/controllers/project/status.go @@ -54,6 +54,7 @@ func (projectStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.Projec func (projectStatusWriter) ApplyResourceStatus(_ logr.Logger, osResource *projects.Project, statusApply *statusApplyT) { resourceStatus := orcapplyconfigv1alpha1.ProjectResourceStatus(). WithName(osResource.Name). + WithDomainID(osResource.DomainID). WithEnabled(osResource.Enabled). WithTags(osResource.Tags...) if osResource.Description != "" { diff --git a/internal/controllers/project/tests/project-create-full/00-assert.yaml b/internal/controllers/project/tests/project-create-full/00-assert.yaml index 25708cfc1..4e38b074a 100644 --- a/internal/controllers/project/tests/project-create-full/00-assert.yaml +++ b/internal/controllers/project/tests/project-create-full/00-assert.yaml @@ -11,3 +11,25 @@ status: tags: - tag1 - tag2 + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: project-create-full + ref: project + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: project-create-full + ref: domain +assertAll: + - celExpr: "project.status.id != ''" + - celExpr: "project.status.resource.domainID == domain.status.id" diff --git a/internal/controllers/project/tests/project-create-full/00-create-resource.yaml b/internal/controllers/project/tests/project-create-full/00-create-resource.yaml index d705e1f6a..0727971b1 100644 --- a/internal/controllers/project/tests/project-create-full/00-create-resource.yaml +++ b/internal/controllers/project/tests/project-create-full/00-create-resource.yaml @@ -1,5 +1,16 @@ --- apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Project metadata: name: project-create-full @@ -11,6 +22,7 @@ spec: resource: name: project-create-full-override description: Project from "create full" test + domainRef: project-create-full enabled: false tags: - tag1 diff --git a/internal/controllers/project/tests/project-create-full/01-assert.yaml b/internal/controllers/project/tests/project-create-full/01-assert.yaml new file mode 100644 index 000000000..8a73533e9 --- /dev/null +++ b/internal/controllers/project/tests/project-create-full/01-assert.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: project-create-full + ref: domain +assertAll: + - celExpr: "domain.status.resource.enabled == false" diff --git a/internal/controllers/project/tests/project-create-full/01-disable-domain.yaml b/internal/controllers/project/tests/project-create-full/01-disable-domain.yaml new file mode 100644 index 000000000..d2c28b34b --- /dev/null +++ b/internal/controllers/project/tests/project-create-full/01-disable-domain.yaml @@ -0,0 +1,7 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-create-full +spec: + resource: + enabled: false diff --git a/internal/controllers/project/tests/project-create-full/README.md b/internal/controllers/project/tests/project-create-full/README.md index abf194158..0e059b6c5 100644 --- a/internal/controllers/project/tests/project-create-full/README.md +++ b/internal/controllers/project/tests/project-create-full/README.md @@ -6,6 +6,12 @@ Create a project using all available fields, and verify that the observed state Also validate that the OpenStack resource uses the name from the spec when it is specified. +## Step 01 + +By default the enabled field is set to true, the enabled field needs to be disabled. + +Disabling the Domain is required before deletion in Openstack. + ## Reference https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/project/tests/project-dependency/00-assert.yaml b/internal/controllers/project/tests/project-dependency/00-assert.yaml index a314a6124..a49448cee 100644 --- a/internal/controllers/project/tests/project-dependency/00-assert.yaml +++ b/internal/controllers/project/tests/project-dependency/00-assert.yaml @@ -13,3 +13,18 @@ status: message: Waiting for Secret/project-dependency to be created status: "True" reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-dependency-no-domain +status: + conditions: + - type: Available + message: Waiting for Domain/project-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Domain/project-dependency to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/project/tests/project-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/project/tests/project-dependency/00-create-resources-missing-deps.yaml index 075fcff47..eb1fedfca 100644 --- a/internal/controllers/project/tests/project-dependency/00-create-resources-missing-deps.yaml +++ b/internal/controllers/project/tests/project-dependency/00-create-resources-missing-deps.yaml @@ -1,6 +1,18 @@ --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Project +metadata: + name: project-dependency-no-domain +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + domainRef: project-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project metadata: name: project-dependency-no-secret spec: diff --git a/internal/controllers/project/tests/project-dependency/00-secret.yaml b/internal/controllers/project/tests/project-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/project/tests/project-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/project/tests/project-dependency/01-assert.yaml b/internal/controllers/project/tests/project-dependency/01-assert.yaml index 0102e1a6e..b018d94db 100644 --- a/internal/controllers/project/tests/project-dependency/01-assert.yaml +++ b/internal/controllers/project/tests/project-dependency/01-assert.yaml @@ -13,3 +13,32 @@ status: message: OpenStack resource is up to date status: "False" reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-dependency-no-domain +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: project-dependency-no-domain + ref: project + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: project-dependency + ref: domain +assertAll: + - celExpr: "project.status.resource.domainID == domain.status.id" diff --git a/internal/controllers/project/tests/project-dependency/01-create-dependencies.yaml b/internal/controllers/project/tests/project-dependency/01-create-dependencies.yaml index 8aaf12e85..13526f11c 100644 --- a/internal/controllers/project/tests/project-dependency/01-create-dependencies.yaml +++ b/internal/controllers/project/tests/project-dependency/01-create-dependencies.yaml @@ -1,5 +1,17 @@ +--- apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - command: kubectl create secret generic project-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} diff --git a/internal/controllers/project/tests/project-dependency/02-assert.yaml b/internal/controllers/project/tests/project-dependency/02-assert.yaml index c41563a86..420d34a33 100644 --- a/internal/controllers/project/tests/project-dependency/02-assert.yaml +++ b/internal/controllers/project/tests/project-dependency/02-assert.yaml @@ -2,10 +2,9 @@ apiVersion: kuttl.dev/v1beta1 kind: TestAssert resourceRefs: - - apiVersion: v1 - kind: Secret + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain name: project-dependency - ref: secret + ref: domain assertAll: - - celExpr: "secret.metadata.deletionTimestamp != 0" - - celExpr: "'openstack.k-orc.cloud/project' in secret.metadata.finalizers" + - celExpr: "domain.status.resource.enabled == false" diff --git a/internal/controllers/project/tests/project-dependency/02-disable-domain.yaml b/internal/controllers/project/tests/project-dependency/02-disable-domain.yaml new file mode 100644 index 000000000..fde38804b --- /dev/null +++ b/internal/controllers/project/tests/project-dependency/02-disable-domain.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-dependency +spec: + resource: + enabled: false diff --git a/internal/controllers/project/tests/project-dependency/03-assert.yaml b/internal/controllers/project/tests/project-dependency/03-assert.yaml index 763703c4c..e4953f1ed 100644 --- a/internal/controllers/project/tests/project-dependency/03-assert.yaml +++ b/internal/controllers/project/tests/project-dependency/03-assert.yaml @@ -1,6 +1,17 @@ +--- apiVersion: kuttl.dev/v1beta1 kind: TestAssert -commands: -# Dependencies that were prevented deletion before should now be gone -- script: "! kubectl get secret project-dependency --namespace $NAMESPACE" - skipLogOutput: true +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: project-dependency + ref: domain + - apiVersion: v1 + kind: Secret + name: project-dependency + ref: secret +assertAll: + - celExpr: "domain.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/project' in domain.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/project' in secret.metadata.finalizers" diff --git a/internal/controllers/project/tests/project-dependency/02-delete-dependencies.yaml b/internal/controllers/project/tests/project-dependency/03-delete-dependencies.yaml similarity index 70% rename from internal/controllers/project/tests/project-dependency/02-delete-dependencies.yaml rename to internal/controllers/project/tests/project-dependency/03-delete-dependencies.yaml index 43755b780..f91ab7b46 100644 --- a/internal/controllers/project/tests/project-dependency/02-delete-dependencies.yaml +++ b/internal/controllers/project/tests/project-dependency/03-delete-dependencies.yaml @@ -1,6 +1,9 @@ +--- apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete domain project-dependency --wait=false + namespaced: true - command: kubectl delete secret project-dependency --wait=false namespaced: true diff --git a/internal/controllers/project/tests/project-dependency/04-assert.yaml b/internal/controllers/project/tests/project-dependency/04-assert.yaml new file mode 100644 index 000000000..13dcb5726 --- /dev/null +++ b/internal/controllers/project/tests/project-dependency/04-assert.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get domain project-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret project-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/project/tests/project-dependency/03-delete-resources.yaml b/internal/controllers/project/tests/project-dependency/04-delete-resources.yaml similarity index 59% rename from internal/controllers/project/tests/project-dependency/03-delete-resources.yaml rename to internal/controllers/project/tests/project-dependency/04-delete-resources.yaml index 7350e392a..95e368a8b 100644 --- a/internal/controllers/project/tests/project-dependency/03-delete-resources.yaml +++ b/internal/controllers/project/tests/project-dependency/04-delete-resources.yaml @@ -1,6 +1,10 @@ +--- apiVersion: kuttl.dev/v1beta1 kind: TestStep delete: - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Project name: project-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: project-dependency-no-domain diff --git a/internal/controllers/project/tests/project-dependency/README.md b/internal/controllers/project/tests/project-dependency/README.md index c0fd0da71..1953a2fed 100644 --- a/internal/controllers/project/tests/project-dependency/README.md +++ b/internal/controllers/project/tests/project-dependency/README.md @@ -10,10 +10,14 @@ Create the missing dependencies and make and verify all the projects are availab ## Step 02 -Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. +Disable the domain dependency to allow KUTTL to cleanup resources without any issues. ## Step 03 +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 04 + Delete the projects and validate that all resources are gone. ## Reference diff --git a/internal/controllers/project/tests/project-import-dependency/00-assert.yaml b/internal/controllers/project/tests/project-import-dependency/00-assert.yaml new file mode 100644 index 000000000..00232e039 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/00-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Domain/project-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Domain/project-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/project/tests/project-import-dependency/00-import-resource.yaml b/internal/controllers/project/tests/project-import-dependency/00-import-resource.yaml new file mode 100644 index 000000000..d7845ab96 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/00-import-resource.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: project-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + domainRef: project-import-dependency diff --git a/internal/controllers/project/tests/project-import-dependency/00-secret.yaml b/internal/controllers/project/tests/project-import-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/project/tests/project-import-dependency/01-assert.yaml b/internal/controllers/project/tests/project-import-dependency/01-assert.yaml new file mode 100644 index 000000000..80aaf3561 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/01-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-import-dependency-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Domain/project-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Domain/project-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/project/tests/project-import-dependency/01-create-trap-resource.yaml b/internal/controllers/project/tests/project-import-dependency/01-create-trap-resource.yaml new file mode 100644 index 000000000..85d3675f9 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/01-create-trap-resource.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# This `project-import-dependency-not-this-one` should not be picked by the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + domainRef: project-import-dependency-not-this-one diff --git a/internal/controllers/project/tests/project-import-dependency/02-assert.yaml b/internal/controllers/project/tests/project-import-dependency/02-assert.yaml new file mode 100644 index 000000000..b07fcffd9 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/02-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: project-import-dependency + ref: project1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: project-import-dependency-not-this-one + ref: project2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: project-import-dependency + ref: domain +assertAll: + - celExpr: "project1.status.id != project2.status.id" + - celExpr: "project1.status.resource.domainID == domain.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-import-dependency +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/project/tests/project-import-dependency/02-create-resource.yaml b/internal/controllers/project/tests/project-import-dependency/02-create-resource.yaml new file mode 100644 index 000000000..b4f7df6a6 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/02-create-resource.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: project-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + domainRef: project-import-dependency-external diff --git a/internal/controllers/project/tests/project-import-dependency/03-assert.yaml b/internal/controllers/project/tests/project-import-dependency/03-assert.yaml new file mode 100644 index 000000000..88ebac977 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/03-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: project-import-dependency-external + ref: domain1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: project-import-dependency-not-this-one + ref: domain2 +assertAll: + - celExpr: "domain1.status.resource.enabled == false" + - celExpr: "domain2.status.resource.enabled == false" diff --git a/internal/controllers/project/tests/project-import-dependency/03-disable-domain.yaml b/internal/controllers/project/tests/project-import-dependency/03-disable-domain.yaml new file mode 100644 index 000000000..163393f1a --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/03-disable-domain.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-import-dependency-external +spec: + resource: + enabled: false +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: project-import-dependency-not-this-one +spec: + resource: + enabled: false diff --git a/internal/controllers/project/tests/project-import-dependency/04-assert.yaml b/internal/controllers/project/tests/project-import-dependency/04-assert.yaml new file mode 100644 index 000000000..4aef05790 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/04-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get domain project-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/project/tests/project-import-dependency/04-delete-import-dependencies.yaml b/internal/controllers/project/tests/project-import-dependency/04-delete-import-dependencies.yaml new file mode 100644 index 000000000..2751ea3af --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/04-delete-import-dependencies.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We should be able to delete the import dependencies + - command: kubectl delete domain project-import-dependency + namespaced: true diff --git a/internal/controllers/project/tests/project-import-dependency/05-assert.yaml b/internal/controllers/project/tests/project-import-dependency/05-assert.yaml new file mode 100644 index 000000000..a81cc4a09 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/05-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get project project-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/project/tests/project-import-dependency/05-delete-resource.yaml b/internal/controllers/project/tests/project-import-dependency/05-delete-resource.yaml new file mode 100644 index 000000000..9a22a4915 --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/05-delete-resource.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: project-import-dependency diff --git a/internal/controllers/project/tests/project-import-dependency/README.md b/internal/controllers/project/tests/project-import-dependency/README.md new file mode 100644 index 000000000..f025cda7c --- /dev/null +++ b/internal/controllers/project/tests/project-import-dependency/README.md @@ -0,0 +1,33 @@ +# Check dependency handling for imported Project + +## Step 00 + +Import a Project that references other imported resources. The referenced imported resources have no matching resources yet. +Verify the Project is waiting for the dependency to be ready. + +## Step 01 + +Create a Project matching the import filter, except for referenced resources, and verify that it's not being imported. + +## Step 02 + +Create the referenced resources and a Project matching the import filters. + +Verify that the observed status on the imported Project corresponds to the spec of the created Project. + +## Step 03 + +Delete the referenced resources and check that ORC does not prevent deletion. The OpenStack resources still exist because they +were imported resources and we only deleted the ORC representation of it. + +## Step 04 + +Delete the Project and validate that all resources are gone. + +## Step 05 + +Disable the domain dependencies so KUTTL can clean the resources without failing. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-dependency diff --git a/internal/controllers/project/zz_generated.adapter.go b/internal/controllers/project/zz_generated.adapter.go index 0d6afee56..f88a3bc8b 100644 --- a/internal/controllers/project/zz_generated.adapter.go +++ b/internal/controllers/project/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package project import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/project/zz_generated.controller.go b/internal/controllers/project/zz_generated.controller.go index 34984c633..7660eb2bb 100644 --- a/internal/controllers/project/zz_generated.controller.go +++ b/internal/controllers/project/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/role/actuator.go b/internal/controllers/role/actuator.go index b278cdd8d..5203a235b 100644 --- a/internal/controllers/role/actuator.go +++ b/internal/controllers/role/actuator.go @@ -18,12 +18,11 @@ package role import ( "context" - "fmt" "iter" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/roles" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -76,30 +75,29 @@ func (actuator roleActuator) ListOSResourcesForAdoption(ctx context.Context, orc Name: getResourceName(orcObject), } + if resourceSpec.DomainRef != nil { + domain, _ := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.DomainRef, "Domain", + func(dep *orcv1alpha1.Domain) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if domain.Status.ID != nil { + listOpts.DomainID = *domain.Status.ID + } + } + return actuator.osClient.ListRoles(ctx, listOpts), true } func (actuator roleActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { var reconcileStatus progress.ReconcileStatus - domain := &orcv1alpha1.Domain{} - if filter.DomainRef != nil { - domainKey := client.ObjectKey{Name: string(*filter.DomainRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, domainKey, domain); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Domain", domainKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching domain %s: %w", domainKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(domain) || domain.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Domain", domainKey.Name, progress.WaitingOnReady)) - } - } - } + domain, rs := dependency.FetchDependency[*orcv1alpha1.Domain]( + ctx, actuator.k8sClient, obj.Namespace, filter.DomainRef, "Domain", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -126,9 +124,7 @@ func (actuator roleActuator) CreateResource(ctx context.Context, obj orcObjectPT var domainID string if resource.DomainRef != nil { domain, domainDepRS := domainDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Domain) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(domainDepRS) if domain != nil { @@ -186,12 +182,10 @@ func (actuator roleActuator) updateResource(ctx context.Context, obj orcObjectPT _, err = actuator.osClient.UpdateRole(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/role/controller.go b/internal/controllers/role/controller.go index faa40bfc0..d4a1b241e 100644 --- a/internal/controllers/role/controller.go +++ b/internal/controllers/role/controller.go @@ -19,6 +19,7 @@ package role import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -40,17 +41,22 @@ const controllerName = "role" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=roles/status,verbs=get;update;patch type roleReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return roleReconcilerConstructor{scopeFactory: scopeFactory} + return &roleReconcilerConstructor{scopeFactory: scopeFactory} } func (roleReconcilerConstructor) GetName() string { return controllerName } +func (c *roleReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + var domainDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.RoleList, *orcv1alpha1.Domain]( "spec.resource.domainRef", func(role *orcv1alpha1.Role) []string { @@ -75,7 +81,7 @@ var domainImportDependency = dependency.NewDependency[*orcv1alpha1.RoleList, *or ) // SetupWithManager sets up the controller with the Manager. -func (c roleReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *roleReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) k8sClient := mgr.GetClient() @@ -109,6 +115,6 @@ func (c roleReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctr return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, roleHelperFactory{}, roleStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, roleHelperFactory{}, roleStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/role/zz_generated.adapter.go b/internal/controllers/role/zz_generated.adapter.go index 3c98f6eca..b87c8d338 100644 --- a/internal/controllers/role/zz_generated.adapter.go +++ b/internal/controllers/role/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package role import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/role/zz_generated.controller.go b/internal/controllers/role/zz_generated.controller.go index e3caa1f35..bc7cce067 100644 --- a/internal/controllers/role/zz_generated.controller.go +++ b/internal/controllers/role/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/roleassignment/actuator.go b/internal/controllers/roleassignment/actuator.go new file mode 100644 index 000000000..d988815e4 --- /dev/null +++ b/internal/controllers/roleassignment/actuator.go @@ -0,0 +1,350 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package roleassignment + +import ( + "context" + "iter" + + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/roles" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// OpenStack resource type +type osResourceT = roles.RoleAssignment + +type roleassignmentActuator struct { + osClient osclients.RoleAssignmentClient + k8sClient client.Client +} + +// buildListOpts constructs a ListAssignmentsOpts from component IDs. +// Only non-empty fields are set, so this works for both exact queries +// (all fields populated) and partial filter queries. +func buildListOpts(roleID, userID, groupID, projectID, domainID string) roles.ListAssignmentsOpts { + // Note: Don't set Effective parameter - it can cause issues with group assignments + listOpts := roles.ListAssignmentsOpts{} + + if roleID != "" { + listOpts.RoleID = roleID + } + if userID != "" { + listOpts.UserID = userID + } + if groupID != "" { + listOpts.GroupID = groupID + } + if projectID != "" { + listOpts.ScopeProjectID = projectID + } + if domainID != "" { + listOpts.ScopeDomainID = domainID + } + + return listOpts +} + +// GetResourceByComponents queries for the role assignment by its tuple (role, actor, scope). +// OpenStack doesn't assign IDs to role assignments - they're identified by this tuple. +// Exactly one of userID/groupID must be set, and exactly one of projectID/domainID must be set. +func (actuator roleassignmentActuator) GetResourceByComponents( + ctx context.Context, + roleID string, + userID string, + groupID string, + projectID string, + domainID string, +) (*osResourceT, progress.ReconcileStatus) { + listOpts := buildListOpts(roleID, userID, groupID, projectID, domainID) + + // Query with exact filters - should return exactly one result + osResource, err := atMostOne(actuator.osClient.ListRoleAssignments(ctx, listOpts), + orcerrors.Terminal(orcv1alpha1.ConditionReasonUnrecoverableError, + "found more than one matching role assignment for the same (role, actor, scope) tuple")) + if err != nil { + return nil, progress.WrapError(err) + } + return osResource, nil +} + +func (actuator roleassignmentActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + // Fetch all dependencies to build the exact filter + var roleID, userID, groupID, projectID, domainID string + + // Role dependency (required) + role, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, &resourceSpec.RoleRef, "Role", + func(dep *orcv1alpha1.Role) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false // Not ready + } + roleID = ptr.Deref(role.Status.ID, "") + + // Actor dependency (user XOR group) + if resourceSpec.UserRef != nil { + user, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.UserRef, "User", + func(dep *orcv1alpha1.User) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false // Not ready + } + userID = ptr.Deref(user.Status.ID, "") + } else { + group, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.GroupRef, "Group", + func(dep *orcv1alpha1.Group) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false // Not ready + } + groupID = ptr.Deref(group.Status.ID, "") + } + + // Scope dependency (project XOR domain) + if resourceSpec.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false // Not ready + } + projectID = ptr.Deref(project.Status.ID, "") + } else { + domain, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.DomainRef, "Domain", + func(dep *orcv1alpha1.Domain) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false // Not ready + } + domainID = ptr.Deref(domain.Status.ID, "") + } + + return actuator.osClient.ListRoleAssignments(ctx, buildListOpts(roleID, userID, groupID, projectID, domainID)), true +} + +func (actuator roleassignmentActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + // Build ListAssignmentsOpts from filter references + var roleID, userID, groupID, projectID, domainID string + + if filter.RoleRef != nil { + role, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, filter.RoleRef, "Role", + func(dep *orcv1alpha1.Role) bool { return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + if role != nil && role.Status.ID != nil { + roleID = *role.Status.ID + } + } + + if filter.UserRef != nil { + user, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, filter.UserRef, "User", + func(dep *orcv1alpha1.User) bool { return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + if user != nil && user.Status.ID != nil { + userID = *user.Status.ID + } + } + + if filter.GroupRef != nil { + group, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, filter.GroupRef, "Group", + func(dep *orcv1alpha1.Group) bool { return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + if group != nil && group.Status.ID != nil { + groupID = *group.Status.ID + } + } + + if filter.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + if project != nil && project.Status.ID != nil { + projectID = *project.Status.ID + } + } + + if filter.DomainRef != nil { + domain, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, filter.DomainRef, "Domain", + func(dep *orcv1alpha1.Domain) bool { return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + if domain != nil && domain.Status.ID != nil { + domainID = *domain.Status.ID + } + } + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + return actuator.osClient.ListRoleAssignments(ctx, buildListOpts(roleID, userID, groupID, projectID, domainID)), nil +} + +func (actuator roleassignmentActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + var reconcileStatus progress.ReconcileStatus + + // Fetch role dependency (required) + role, roleDepRS := roleDependency.GetDependency( + ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Role) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(roleDepRS) + var roleID string + if role != nil { + roleID = ptr.Deref(role.Status.ID, "") + } + + // Fetch actor dependency (user XOR group) + var userID, groupID string + if resource.UserRef != nil { + user, userDepRS := userDependency.GetDependency( + ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.User) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(userDepRS) + if user != nil { + userID = ptr.Deref(user.Status.ID, "") + } + } else { + group, groupDepRS := groupDependency.GetDependency( + ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Group) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(groupDepRS) + if group != nil { + groupID = ptr.Deref(group.Status.ID, "") + } + } + + // Fetch scope dependency (project XOR domain) + var projectID, domainID string + if resource.ProjectRef != nil { + project, projectDepRS := projectDependency.GetDependency( + ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) + if project != nil { + projectID = ptr.Deref(project.Status.ID, "") + } + } else { + domain, domainDepRS := domainDependency.GetDependency( + ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Domain) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(domainDepRS) + if domain != nil { + domainID = ptr.Deref(domain.Status.ID, "") + } + } + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + // Build AssignOpts + assignOpts := roles.AssignOpts{ + UserID: userID, + GroupID: groupID, + ProjectID: projectID, + DomainID: domainID, + } + + // Assign the role (idempotent - returns 204 even if already exists) + err := actuator.osClient.AssignRole(ctx, roleID, assignOpts) + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating role assignment: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + // Verify the assignment was created by listing with exact filters + osResource, verifyErr := atMostOne(actuator.osClient.ListRoleAssignments(ctx, buildListOpts(roleID, userID, groupID, projectID, domainID)), + orcerrors.Terminal(orcv1alpha1.ConditionReasonUnrecoverableError, + "found more than one matching role assignment after creation")) + if verifyErr != nil { + return nil, progress.WrapError(verifyErr) + } + if osResource == nil { + // This shouldn't happen - we just assigned it + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonUnrecoverableError, + "role assignment succeeded but could not be found in OpenStack")) + } + return osResource, nil +} + +func (actuator roleassignmentActuator) DeleteResource(ctx context.Context, _ orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + // Build UnassignOpts from the osResource + unassignOpts := roles.UnassignOpts{ + UserID: osResource.User.ID, + GroupID: osResource.Group.ID, + ProjectID: osResource.Scope.Project.ID, + DomainID: osResource.Scope.Domain.ID, + } + + return progress.WrapError(actuator.osClient.UnassignRole(ctx, osResource.Role.ID, unassignOpts)) +} diff --git a/internal/controllers/roleassignment/actuator_test.go b/internal/controllers/roleassignment/actuator_test.go new file mode 100644 index 000000000..2ddc49467 --- /dev/null +++ b/internal/controllers/roleassignment/actuator_test.go @@ -0,0 +1,418 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package roleassignment + +import ( + "context" + "errors" + "fmt" + "iter" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/roles" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" +) + +var ( + errNotImplemented = errors.New("not implemented") + errTest = errors.New("test error") +) + +const ( + testNamespace = "test-ns" + testRoleName = "test-role" + testUserName = "test-user" + testGroupName = "test-group" + testProjectName = "test-project" + testDomainName = "test-domain" +) + +// mockRoleAssignmentClient is a simple mock that returns pre-configured assignments. +type mockRoleAssignmentClient struct { + assignments []roles.RoleAssignment +} + +var _ osclients.RoleAssignmentClient = mockRoleAssignmentClient{} + +func (m mockRoleAssignmentClient) ListRoleAssignments(_ context.Context, _ roles.ListAssignmentsOpts) iter.Seq2[*roles.RoleAssignment, error] { + return func(yield func(*roles.RoleAssignment, error) bool) { + for i := range m.assignments { + if !yield(&m.assignments[i], nil) { + return + } + } + } +} + +func (m mockRoleAssignmentClient) AssignRole(_ context.Context, _ string, _ roles.AssignOpts) error { + return errNotImplemented +} + +func (m mockRoleAssignmentClient) UnassignRole(_ context.Context, _ string, _ roles.UnassignOpts) error { + return errNotImplemented +} + +// Test result type and check helpers + +type raResult struct { + assignment *roles.RoleAssignment + err error +} + +type checkFunc func([]raResult) error + +func checks(fns ...checkFunc) []checkFunc { return fns } + +func noError(results []raResult) error { + for _, result := range results { + if result.err != nil { + return fmt.Errorf("unexpected error: %w", result.err) + } + } + return nil +} + +func wantError(wantErr error) checkFunc { + return func(results []raResult) error { + for _, result := range results { + if result.err != nil && errors.Is(result.err, wantErr) { + return nil + } + } + return fmt.Errorf("expected error %v not found in results", wantErr) + } +} + +func findsN(wantN int) checkFunc { + return func(results []raResult) error { + found := len(results) + if found != wantN { + return fmt.Errorf("expected %d results, got %d", wantN, found) + } + return nil + } +} + +// availableCondition returns an Available=True condition for test objects. +func availableCondition() metav1.Condition { + return metav1.Condition{ + Type: orcv1alpha1.ConditionAvailable, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Now(), + Reason: "Available", + } +} + +// newFakeK8sClient creates a fake k8s client with the given objects and ORC scheme. +func newFakeK8sClient(objects ...client.Object) client.Client { + scheme := runtime.NewScheme() + _ = orcv1alpha1.AddToScheme(scheme) + + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(objects...). + Build() +} + +// availableRole returns a Role object that is available with the given status ID. +func availableRole(statusID string) *orcv1alpha1.Role { + return &orcv1alpha1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: testRoleName, + Namespace: testNamespace, + }, + Status: orcv1alpha1.RoleStatus{ + Conditions: []metav1.Condition{availableCondition()}, + ID: ptr.To(statusID), + }, + } +} + +// availableUser returns a User object that is available with the given status ID. +func availableUser(statusID string) *orcv1alpha1.User { + return &orcv1alpha1.User{ + ObjectMeta: metav1.ObjectMeta{ + Name: testUserName, + Namespace: testNamespace, + }, + Status: orcv1alpha1.UserStatus{ + Conditions: []metav1.Condition{availableCondition()}, + ID: ptr.To(statusID), + }, + } +} + +// availableGroup returns a Group object that is available with the given status ID. +func availableGroup(statusID string) *orcv1alpha1.Group { + return &orcv1alpha1.Group{ + ObjectMeta: metav1.ObjectMeta{ + Name: testGroupName, + Namespace: testNamespace, + }, + Status: orcv1alpha1.GroupStatus{ + Conditions: []metav1.Condition{availableCondition()}, + ID: ptr.To(statusID), + }, + } +} + +// availableProject returns a Project object that is available with the given status ID. +func availableProject(statusID string) *orcv1alpha1.Project { + return &orcv1alpha1.Project{ + ObjectMeta: metav1.ObjectMeta{ + Name: testProjectName, + Namespace: testNamespace, + }, + Status: orcv1alpha1.ProjectStatus{ + Conditions: []metav1.Condition{availableCondition()}, + ID: ptr.To(statusID), + }, + } +} + +// availableDomain returns a Domain object that is available with the given status ID. +func availableDomain(statusID string) *orcv1alpha1.Domain { + return &orcv1alpha1.Domain{ + ObjectMeta: metav1.ObjectMeta{ + Name: testDomainName, + Namespace: testNamespace, + }, + Status: orcv1alpha1.DomainStatus{ + Conditions: []metav1.Condition{availableCondition()}, + ID: ptr.To(statusID), + }, + } +} + +func TestListOSResourcesForAdoption(t *testing.T) { + userProjectAssignment := roles.RoleAssignment{ + Role: roles.AssignedRole{ID: "role-id-1"}, + User: roles.User{ID: "user-id-1"}, + Scope: roles.Scope{Project: roles.Project{ID: "project-id-1"}}, + } + + groupDomainAssignment := roles.RoleAssignment{ + Role: roles.AssignedRole{ID: "role-id-2"}, + Group: roles.Group{ID: "group-id-2"}, + Scope: roles.Scope{Domain: roles.Domain{ID: "domain-id-2"}}, + } + + for _, tc := range [...]struct { + name string + orcObject *orcv1alpha1.RoleAssignment + k8sObjects []client.Object + osClient osclients.RoleAssignmentClient + wantAdopt bool + checks []checkFunc + }{ + { + name: "returns false when spec.resource is nil", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{}, + }, + osClient: mockRoleAssignmentClient{}, + wantAdopt: false, + }, + { + name: "user+project scope, all deps available, match found", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{ + Resource: &orcv1alpha1.RoleAssignmentResourceSpec{ + RoleRef: "test-role", + UserRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-user"), + ProjectRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-project"), + }, + }, + }, + k8sObjects: []client.Object{ + availableRole("role-id-1"), + availableUser("user-id-1"), + availableProject("project-id-1"), + }, + osClient: mockRoleAssignmentClient{assignments: []roles.RoleAssignment{userProjectAssignment}}, + wantAdopt: true, + checks: checks(noError, findsN(1)), + }, + { + name: "group+domain scope, all deps available, match found", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{ + Resource: &orcv1alpha1.RoleAssignmentResourceSpec{ + RoleRef: "test-role", + GroupRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-group"), + DomainRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-domain"), + }, + }, + }, + k8sObjects: []client.Object{ + availableRole("role-id-2"), + availableGroup("group-id-2"), + availableDomain("domain-id-2"), + }, + osClient: mockRoleAssignmentClient{assignments: []roles.RoleAssignment{groupDomainAssignment}}, + wantAdopt: true, + checks: checks(noError, findsN(1)), + }, + { + name: "all deps available, no matches from OS", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{ + Resource: &orcv1alpha1.RoleAssignmentResourceSpec{ + RoleRef: "test-role", + UserRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-user"), + ProjectRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-project"), + }, + }, + }, + k8sObjects: []client.Object{ + availableRole("role-id-1"), + availableUser("user-id-2"), + availableProject("project-id-2"), + }, + osClient: mockRoleAssignmentClient{assignments: []roles.RoleAssignment{}}, + wantAdopt: true, + checks: checks(noError, findsN(0)), + }, + { + name: "role dependency not found, returns false", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{ + Resource: &orcv1alpha1.RoleAssignmentResourceSpec{ + RoleRef: "missing-role", + UserRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-user"), + ProjectRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-project"), + }, + }, + }, + k8sObjects: []client.Object{ + // role is missing + availableUser("user-id-1"), + availableProject("project-id-1"), + }, + // OS client has a match — must NOT be queried + osClient: mockRoleAssignmentClient{assignments: []roles.RoleAssignment{userProjectAssignment}}, + wantAdopt: false, + }, + { + name: "user dependency not ready, returns false", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{ + Resource: &orcv1alpha1.RoleAssignmentResourceSpec{ + RoleRef: "test-role", + UserRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-user"), + ProjectRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-project"), + }, + }, + }, + k8sObjects: []client.Object{ + availableRole("role-id-1"), + // user exists but is not available (no Available condition, no Status.ID) + &orcv1alpha1.User{ + ObjectMeta: metav1.ObjectMeta{Name: "test-user", Namespace: testNamespace}, + }, + availableProject("project-id-1"), + }, + osClient: mockRoleAssignmentClient{assignments: []roles.RoleAssignment{userProjectAssignment}}, + wantAdopt: false, + }, + { + name: "project dependency not found, returns false", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{ + Resource: &orcv1alpha1.RoleAssignmentResourceSpec{ + RoleRef: "test-role", + GroupRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-group"), + ProjectRef: ptr.To[orcv1alpha1.KubernetesNameRef]("missing-project"), + }, + }, + }, + k8sObjects: []client.Object{ + availableRole("role-id-2"), + availableGroup("group-id-2"), + // project is missing + }, + osClient: mockRoleAssignmentClient{assignments: []roles.RoleAssignment{groupDomainAssignment}}, + wantAdopt: false, + }, + { + name: "OS client returns error", + orcObject: &orcv1alpha1.RoleAssignment{ + ObjectMeta: metav1.ObjectMeta{Name: "test-ra", Namespace: testNamespace}, + Spec: orcv1alpha1.RoleAssignmentSpec{ + Resource: &orcv1alpha1.RoleAssignmentResourceSpec{ + RoleRef: "test-role", + UserRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-user"), + ProjectRef: ptr.To[orcv1alpha1.KubernetesNameRef]("test-project"), + }, + }, + }, + k8sObjects: []client.Object{ + availableRole("role-id-1"), + availableUser("user-id-1"), + availableProject("project-id-1"), + }, + osClient: osclients.NewRoleAssignmentErrorClient(errTest), + wantAdopt: true, + checks: checks(wantError(errTest)), + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + + k8sClient := newFakeK8sClient(tc.k8sObjects...) + + actuator := roleassignmentActuator{ + osClient: tc.osClient, + k8sClient: k8sClient, + } + + resourceIter, canAdopt := actuator.ListOSResourcesForAdoption(ctx, tc.orcObject) + if canAdopt != tc.wantAdopt { + t.Fatalf("canAdopt = %v, want %v", canAdopt, tc.wantAdopt) + } + + if !canAdopt { + return + } + + var results []raResult + for assignment, err := range resourceIter { + results = append(results, raResult{assignment, err}) + } + + for _, check := range tc.checks { + if e := check(results); e != nil { + t.Error(e) + } + } + }) + } +} diff --git a/internal/controllers/roleassignment/controller.go b/internal/controllers/roleassignment/controller.go new file mode 100644 index 000000000..24409089d --- /dev/null +++ b/internal/controllers/roleassignment/controller.go @@ -0,0 +1,292 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package roleassignment + +import ( + "context" + "errors" + "time" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "roleassignment" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=roleassignments,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=roleassignments/status,verbs=get;update;patch + +type roleassignmentReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return &roleassignmentReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (roleassignmentReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *roleassignmentReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var roleDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Role]( + "spec.resource.roleRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Resource + if resource == nil { + return nil + } + return []string{string(resource.RoleRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var userDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.User]( + "spec.resource.userRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Resource + if resource == nil || resource.UserRef == nil { + return nil + } + return []string{string(*resource.UserRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var groupDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Group]( + "spec.resource.groupRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Resource + if resource == nil || resource.GroupRef == nil { + return nil + } + return []string{string(*resource.GroupRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var projectDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Project]( + "spec.resource.projectRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Resource + if resource == nil || resource.ProjectRef == nil { + return nil + } + return []string{string(*resource.ProjectRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var domainDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Domain]( + "spec.resource.domainRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Resource + if resource == nil || resource.DomainRef == nil { + return nil + } + return []string{string(*resource.DomainRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var roleImportDependency = dependency.NewDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Role]( + "spec.import.filter.roleRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.RoleRef == nil { + return nil + } + return []string{string(*resource.Filter.RoleRef)} + }, +) + +var userImportDependency = dependency.NewDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.User]( + "spec.import.filter.userRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.UserRef == nil { + return nil + } + return []string{string(*resource.Filter.UserRef)} + }, +) + +var groupImportDependency = dependency.NewDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Group]( + "spec.import.filter.groupRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.GroupRef == nil { + return nil + } + return []string{string(*resource.Filter.GroupRef)} + }, +) + +var projectImportDependency = dependency.NewDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Project]( + "spec.import.filter.projectRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.ProjectRef == nil { + return nil + } + return []string{string(*resource.Filter.ProjectRef)} + }, +) + +var domainImportDependency = dependency.NewDependency[*orcv1alpha1.RoleAssignmentList, *orcv1alpha1.Domain]( + "spec.import.filter.domainRef", + func(roleassignment *orcv1alpha1.RoleAssignment) []string { + resource := roleassignment.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.DomainRef == nil { + return nil + } + return []string{string(*resource.Filter.DomainRef)} + }, +) + +// SetupWithManager sets up the controller with the Manager. +func (c roleassignmentReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + roleWatchEventHandler, err := roleDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + userWatchEventHandler, err := userDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + groupWatchEventHandler, err := groupDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + projectWatchEventHandler, err := projectDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + domainWatchEventHandler, err := domainDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + roleImportWatchEventHandler, err := roleImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + userImportWatchEventHandler, err := userImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + groupImportWatchEventHandler, err := groupImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + projectImportWatchEventHandler, err := projectImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + domainImportWatchEventHandler, err := domainImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + Watches(&orcv1alpha1.Role{}, roleWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Role{})), + ). + Watches(&orcv1alpha1.User{}, userWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.User{})), + ). + Watches(&orcv1alpha1.Group{}, groupWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Group{})), + ). + Watches(&orcv1alpha1.Project{}, projectWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ). + Watches(&orcv1alpha1.Domain{}, domainWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Domain{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Role{}, roleImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Role{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.User{}, userImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.User{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Group{}, groupImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Group{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Project{}, projectImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Domain{}, domainImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Domain{})), + ). + For(&orcv1alpha1.RoleAssignment{}) + + if err := errors.Join( + roleDependency.AddToManager(ctx, mgr), + userDependency.AddToManager(ctx, mgr), + groupDependency.AddToManager(ctx, mgr), + projectDependency.AddToManager(ctx, mgr), + domainDependency.AddToManager(ctx, mgr), + roleImportDependency.AddToManager(ctx, mgr), + userImportDependency.AddToManager(ctx, mgr), + groupImportDependency.AddToManager(ctx, mgr), + projectImportDependency.AddToManager(ctx, mgr), + domainImportDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + // Custom reconciler for role assignments (relationships, not resources with IDs) + reconciler := &roleassignmentReconciler{ + client: mgr.GetClient(), + scopeFactory: c.scopeFactory, + defaultResyncPeriod: c.defaultResyncPeriod, + } + return builder.Complete(reconciler) +} diff --git a/internal/controllers/roleassignment/reconciler.go b/internal/controllers/roleassignment/reconciler.go new file mode 100644 index 000000000..17c8f8849 --- /dev/null +++ b/internal/controllers/roleassignment/reconciler.go @@ -0,0 +1,421 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package roleassignment + +import ( + "context" + "fmt" + "iter" + "time" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/resync" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/status" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/finalizers" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +const ( + // The time to wait before reconciling again when we are waiting for some change in OpenStack + externalUpdatePollingPeriod = 15 * time.Second +) + +// roleassignmentReconciler reconciles RoleAssignment objects. +// Unlike other ORC resources, role assignments are relationships (not resources with IDs), +// so this uses a custom reconciler instead of the generic framework. +type roleassignmentReconciler struct { + client client.Client + scopeFactory scope.Factory + defaultResyncPeriod time.Duration + + statusWriter roleassignmentStatusWriter +} + +func (r *roleassignmentReconciler) GetName() string { return controllerName } +func (r *roleassignmentReconciler) GetK8sClient() client.Client { return r.client } +func (r *roleassignmentReconciler) GetScopeFactory() scope.Factory { return r.scopeFactory } + +// Reconcile is the main entry point for reconciliation. +// It fetches the RoleAssignment object and routes to either reconcileNormal or reconcileDelete. +func (r *roleassignmentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + orcObject := new(orcObjectT) + err := r.client.Get(ctx, req.NamespacedName, orcObject) + if err != nil { + if apierrors.IsNotFound(err) { + // Object deleted, nothing to do + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + log := ctrl.LoggerFrom(ctx) + + // Check if object is being deleted + if !orcObject.GetDeletionTimestamp().IsZero() { + return r.reconcileDelete(ctx, orcObject).Return(log) + } + + return r.reconcileNormal(ctx, orcObject).Return(log) +} + +func hasRoleAssignmentComponents(statusResource *orcv1alpha1.RoleAssignmentResourceStatus) bool { + return statusResource != nil && + statusResource.RoleID != "" && + (statusResource.UserID != "" || statusResource.GroupID != "") && + (statusResource.ProjectID != "" || statusResource.DomainID != "") +} + +// reconcileNormal handles the normal reconciliation flow: +// 1. Check if we should reconcile (based on Progressing condition) +// 2. Create actuator (OpenStack client) +// 3. Get or create the role assignment +// 4. Update status +func (r *roleassignmentReconciler) reconcileNormal(ctx context.Context, orcObject orcObjectPT) (reconcileStatus progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + effectiveResyncPeriod := resync.DetermineResyncPeriod(orcObject.Spec.ResyncPeriod, r.defaultResyncPeriod) + + // Check if we should skip reconciliation + if !reconciler.ShouldReconcile(orcObject, orcObject.Status.LastSyncTime, effectiveResyncPeriod) { + log.V(logging.Verbose).Info("Status is up to date: not reconciling") + if remaining := resync.RemainingUntilNextSync(orcObject.Status.LastSyncTime, effectiveResyncPeriod); remaining > 0 { + return reconcileStatus.WithRequeue(remaining) + } + return reconcileStatus + } + + log.V(logging.Verbose).Info("Reconciling role assignment") + + var osResource *osResourceT + + // Ensure we always update status at the end + defer func() { + reconcileStatus = reconcileStatus.WithReconcileStatus( + status.UpdateStatus(ctx, r, r.statusWriter, orcObject, osResource, reconcileStatus)) + }() + + // Phase 3: Add finalizer if not present + if !controllerutil.ContainsFinalizer(orcObject, finalizer) { + patch := finalizers.SetFinalizerPatch(orcObject, finalizer) + if err := r.client.Patch(ctx, orcObject, patch, client.ForceOwnership, orcstrings.GetSSAFieldOwnerWithTxn(controllerName, orcstrings.SSATransactionFinalizer)); err != nil { + return progress.WrapError(fmt.Errorf("setting finalizer: %w", err)) + } + } + + // Phase 3: Create actuator + actuator, actuatorRS := r.newActuator(ctx, orcObject) + if needsReschedule, err := actuatorRS.NeedsReschedule(); needsReschedule { + if err == nil { + log.V(logging.Verbose).Info("Waiting on events before creation") + } + return actuatorRS.WithReconcileStatus(reconcileStatus) + } + + // Phase 4: Check if role assignment exists using Status.Resource components + if orcObject.Status.Resource != nil { + statusResource := orcObject.Status.Resource + // If we have all components in status, try to fetch the role assignment + if hasRoleAssignmentComponents(statusResource) { + osResource, getRS := actuator.GetResourceByComponents( + ctx, + statusResource.RoleID, + statusResource.UserID, + statusResource.GroupID, + statusResource.ProjectID, + statusResource.DomainID, + ) + if needsReschedule, _ := getRS.NeedsReschedule(); needsReschedule { + return getRS.WithReconcileStatus(reconcileStatus) + } + + if osResource != nil { + log.V(logging.Verbose).Info("Got existing role assignment") + } else { + // Status was fully populated but the resource no longer exists in + // OpenStack. GetResourceByComponents uses a LIST query which returns + // (nil, nil) for empty results rather than a 404 error, so we detect + // deletion here. + if orcObject.Spec.ManagementPolicy == orcv1alpha1.ManagementPolicyUnmanaged { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonUnrecoverableError, "role assignment has been deleted from OpenStack")) + } + log.V(logging.Info).Info("Role assignment was deleted externally; will recreate") + } + } + } + + // Phase 5: Import by filter + if osResource == nil { + if importSpec := orcObject.Spec.Import; importSpec != nil { + if filter := importSpec.Filter; filter != nil { + resourceIter, importRS := actuator.ListOSResourcesForImport(ctx, orcObject, *filter) + if needsReschedule, _ := importRS.NeedsReschedule(); needsReschedule { + return importRS.WithReconcileStatus(reconcileStatus) + } + + var err error + osResource, err = atMostOne(resourceIter, + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, + "found more than one matching OpenStack resource during import")) + if err != nil { + return progress.WrapError(err) + } + + if osResource == nil { + return progress.WaitingOnOpenStack(progress.WaitingOnCreation, externalUpdatePollingPeriod) + } + + log.V(logging.Info).Info("Imported role assignment") + } + } + } + + // Phase 6: Adoption - check for existing resource before creating + if osResource == nil { + if orcObject.Spec.ManagementPolicy == orcv1alpha1.ManagementPolicyUnmanaged { + // We never create an unmanaged resource + // API validation should have ensured that one of the above functions returned + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Not creating unmanaged resource")) + } + + if resourceIter, canAdopt := actuator.ListOSResourcesForAdoption(ctx, orcObject); canAdopt { + var err error + osResource, err = atMostOne(resourceIter, + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, + "found more than one matching OpenStack resource during adoption")) + if err != nil { + return progress.WrapError(err) + } + if osResource != nil { + log.V(logging.Info).Info("Adopted previously created resource") + } + } + } + + // Phase 7: Fetch dependencies and create role assignment + if osResource == nil { + log.V(logging.Info).Info("Creating resource") + var createRS progress.ReconcileStatus + osResource, createRS = actuator.CreateResource(ctx, orcObject) + if needsReschedule, err := createRS.NeedsReschedule(); needsReschedule { + if err == nil { + log.V(logging.Verbose).Info("Waiting on dependencies or creation") + } + return createRS.WithReconcileStatus(reconcileStatus) + } + + if osResource == nil { + return reconcileStatus.WithError(fmt.Errorf("osResource is not set, but no wait events or error")) + } + + log.V(logging.Info).Info("Role assignment created") + } + + if resync.ShouldScheduleResync(effectiveResyncPeriod, reconcileStatus) { + reconcileStatus = reconcileStatus.WithRequeue(resync.CalculateJitteredDuration(effectiveResyncPeriod)) + } + return reconcileStatus +} + +// atMostOne returns the first element from the iterator, or nil if it's empty. +// It returns multipleErr if the iterator yields more than one element. +func atMostOne(resourceIter iter.Seq2[*osResourceT, error], multipleErr error) (*osResourceT, error) { + next, stop := iter.Pull2(resourceIter) + defer stop() + + // Try to fetch the first result + osResource, err, ok := next() + if err != nil { + return nil, err + } else if !ok { + // No first result + return nil, nil + } + + // Check that there are no other results + _, err, ok = next() + if err != nil { + return nil, err + } else if ok { + return nil, multipleErr + } + + return osResource, nil +} + +// reconcileDelete handles deletion of the RoleAssignment: +// 1. Check finalizer +// 2. Fetch the role assignment (using Status.Resource components) +// 3. Check management policy +// 4. Delete from OpenStack +// 5. Remove finalizer +func (r *roleassignmentReconciler) reconcileDelete(ctx context.Context, orcObject orcObjectPT) (reconcileStatus progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + log.V(logging.Verbose).Info("Reconciling role assignment delete") + + var osResource *osResourceT + deleted := false + + // Update status unless we've removed the finalizer + defer func() { + if !deleted { + reconcileStatus = reconcileStatus.WithReconcileStatus( + status.UpdateStatus(ctx, r, r.statusWriter, orcObject, osResource, reconcileStatus)) + } + }() + + // Check if our finalizer is present + var foundFinalizer bool + for _, f := range orcObject.GetFinalizers() { + if f == finalizer { + foundFinalizer = true + } else { + reconcileStatus = reconcileStatus.WaitingOnFinalizer(f) + } + } + + // Cleanup not required if our finalizer is not present + if !foundFinalizer { + return reconcileStatus + } + + if needsReschedule, err := reconcileStatus.NeedsReschedule(); needsReschedule { + if err == nil { + log.V(logging.Verbose).Info("Deferring resource cleanup due to remaining external finalizers") + } + return reconcileStatus + } + + removeFinalizer := func(reconcileStatus progress.ReconcileStatus) progress.ReconcileStatus { + if err := r.client.Patch(ctx, orcObject, finalizers.RemoveFinalizerPatch(orcObject), orcstrings.GetSSAFieldOwnerWithTxn(controllerName, orcstrings.SSATransactionFinalizer)); err != nil { + return reconcileStatus.WithError(fmt.Errorf("removing finalizer: %w", err)) + } + deleted = true + return reconcileStatus + } + + // Check management policy + managementPolicy := orcObject.Spec.ManagementPolicy + managedOptions := orcObject.Spec.ManagedOptions + if managementPolicy == orcv1alpha1.ManagementPolicyUnmanaged || managedOptions.GetOnDelete() == orcv1alpha1.OnDeleteDetach { + logPolicy := []any{"managementPolicy", managementPolicy} + if managementPolicy == orcv1alpha1.ManagementPolicyManaged { + logPolicy = append(logPolicy, "onDelete", managedOptions.GetOnDelete()) + } + log.V(logging.Verbose).Info("Not deleting OpenStack resource due to policy", logPolicy...) + return removeFinalizer(reconcileStatus) + } + + // Create actuator for OpenStack operations + actuator, actuatorRS := r.newActuator(ctx, orcObject) + if needsReschedule, err := actuatorRS.NeedsReschedule(); needsReschedule { + if err == nil { + log.V(logging.Verbose).Info("Waiting on events before deletion") + } + return actuatorRS.WithReconcileStatus(reconcileStatus) + } + + // Fetch the role assignment using Status.Resource components + if orcObject.Status.Resource != nil { + statusResource := orcObject.Status.Resource + if statusResource.RoleID != "" && + (statusResource.UserID != "" || statusResource.GroupID != "") && + (statusResource.ProjectID != "" || statusResource.DomainID != "") { + + var getRS progress.ReconcileStatus + osResource, getRS = actuator.GetResourceByComponents( + ctx, + statusResource.RoleID, + statusResource.UserID, + statusResource.GroupID, + statusResource.ProjectID, + statusResource.DomainID, + ) + if needsReschedule, err := getRS.NeedsReschedule(); needsReschedule { + // NotFound is our success condition for delete + if err == nil || !orcerrors.IsNotFound(err) { + return getRS.WithReconcileStatus(reconcileStatus) + } + osResource = nil + } + } + } + + // If status was never populated, check for orphaned resources via adoption + if osResource == nil && orcObject.Status.Resource == nil { + resourceIter, canAdopt := actuator.ListOSResourcesForAdoption(ctx, orcObject) + if canAdopt { + var err error + osResource, err = atMostOne(resourceIter, + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, + "found more than one matching OpenStack resource during adoption")) + if err != nil { + return reconcileStatus.WithError(err) + } + } + } + + if osResource == nil { + log.V(logging.Info).Info("Role assignment deletion confirmed") + return removeFinalizer(reconcileStatus) + } + + log.V(logging.Info).Info("Deleting role assignment from OpenStack") + deleteRS := actuator.DeleteResource(ctx, orcObject, osResource) + if needsReschedule, _ := deleteRS.NeedsReschedule(); needsReschedule { + return deleteRS.WithReconcileStatus(reconcileStatus) + } + + log.V(logging.Info).Info("Role assignment deletion confirmed") + return removeFinalizer(reconcileStatus) +} + +// newActuator creates a roleassignmentActuator with OpenStack client setup. +func (r *roleassignmentReconciler) newActuator(ctx context.Context, orcObject orcObjectPT) (roleassignmentActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, r.client, orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return roleassignmentActuator{}, reconcileStatus + } + + clientScope, err := r.scopeFactory.NewClientScopeFromObject(ctx, r.client, log, orcObject) + if err != nil { + return roleassignmentActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewRoleAssignmentClient() + if err != nil { + return roleassignmentActuator{}, progress.WrapError(err) + } + + return roleassignmentActuator{ + osClient: osClient, + k8sClient: r.client, + }, nil +} diff --git a/internal/controllers/roleassignment/status.go b/internal/controllers/roleassignment/status.go new file mode 100644 index 000000000..2a938e9e7 --- /dev/null +++ b/internal/controllers/roleassignment/status.go @@ -0,0 +1,83 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package roleassignment + +import ( + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type roleassignmentStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.RoleAssignmentApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.RoleAssignmentStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.RoleAssignment, *osResourceT, *objectApplyT, *statusApplyT] = roleassignmentStatusWriter{} + +func (roleassignmentStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.RoleAssignment(name, namespace) +} + +// ResourceAvailableStatus returns the availability status of the role assignment. +// Role assignments don't have Status.ID, so availability is based on osResource +// presence and status component fields. +func (roleassignmentStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.RoleAssignment, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource != nil { + return metav1.ConditionTrue, nil + } + + // If we previously observed component IDs but can't fetch the resource now, + // report Unknown since we can't confirm availability. + if orcObject.Status.Resource != nil && + (orcObject.Status.Resource.RoleID != "" || + orcObject.Status.Resource.UserID != "" || + orcObject.Status.Resource.GroupID != "" || + orcObject.Status.Resource.ProjectID != "" || + orcObject.Status.Resource.DomainID != "") { + return metav1.ConditionUnknown, nil + } + + return metav1.ConditionFalse, nil +} + +// ApplyResourceStatus writes the role assignment component IDs to status. +func (roleassignmentStatusWriter) ApplyResourceStatus(_ logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.RoleAssignmentResourceStatus() + + if osResource.Role.ID != "" { + resourceStatus.WithRoleID(osResource.Role.ID) + } + if osResource.User.ID != "" { + resourceStatus.WithUserID(osResource.User.ID) + } + if osResource.Group.ID != "" { + resourceStatus.WithGroupID(osResource.Group.ID) + } + if osResource.Scope.Project.ID != "" { + resourceStatus.WithProjectID(osResource.Scope.Project.ID) + } + if osResource.Scope.Domain.ID != "" { + resourceStatus.WithDomainID(osResource.Scope.Domain.ID) + } + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-assert.yaml new file mode 100644 index 000000000..594f22e3f --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-assert.yaml @@ -0,0 +1,75 @@ +--- +# Assert Role is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-gd-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert Group is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Group +metadata: + name: roleassignment-gd-test-group +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert Domain is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-gd-test-domain +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert RoleAssignment is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-group-domain +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Validate RoleAssignment status fields +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-group-domain + ref: roleassignment +assertAll: + # Verify status.id is NOT set (role assignments use component-based identification) + - celExpr: "!has(roleassignment.status.id) || roleassignment.status.id == ''" + # Verify all component IDs are populated in status.resource + - celExpr: "roleassignment.status.resource.roleID != ''" + - celExpr: "roleassignment.status.resource.groupID != ''" + - celExpr: "roleassignment.status.resource.domainID != ''" + # Verify user and project are not set (since we used group and domain) + - celExpr: "!has(roleassignment.status.resource.userID) || roleassignment.status.resource.userID == ''" + - celExpr: "!has(roleassignment.status.resource.projectID) || roleassignment.status.resource.projectID == ''" diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-create-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-create-resource.yaml new file mode 100644 index 000000000..a0fae8d95 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-create-resource.yaml @@ -0,0 +1,54 @@ +--- +# Create a test role +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-gd-test-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-gd-test-role +--- +# Create a test group +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Group +metadata: + name: roleassignment-gd-test-group +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-gd-test-group +--- +# Create a test domain +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-gd-test-domain +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-gd-test-domain +--- +# Create role assignment (group on domain) +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-group-domain +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-gd-test-role + groupRef: roleassignment-gd-test-group + domainRef: roleassignment-gd-test-domain diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/01-assert.yaml new file mode 100644 index 000000000..5470f499b --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/01-assert.yaml @@ -0,0 +1,9 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: roleassignment-gd-test-domain + ref: domain +assertAll: + - celExpr: "domain.status.resource.enabled == false" \ No newline at end of file diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/01-disable-domain.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/01-disable-domain.yaml new file mode 100644 index 000000000..fccf56038 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/01-disable-domain.yaml @@ -0,0 +1,7 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-gd-test-domain +spec: + resource: + enabled: false \ No newline at end of file diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/02-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/02-assert.yaml new file mode 100644 index 000000000..64fc769bf --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/02-assert.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Verify RoleAssignment is deleted +- script: "! kubectl get roleassignment roleassignment-create-group-domain --namespace $NAMESPACE" + skipLogOutput: true +--- +# Verify dependencies still exist (deletion guard should keep them) +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-gd-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Group +metadata: + name: roleassignment-gd-test-group +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-gd-test-domain +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/02-delete-roleassignment.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/02-delete-roleassignment.yaml new file mode 100644 index 000000000..e3554c56b --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/02-delete-roleassignment.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-group-domain diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/README.md b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/README.md new file mode 100644 index 000000000..ec03542bb --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-domain/README.md @@ -0,0 +1,15 @@ +# Create a RoleAssignment for Group on Domain + +## Step 00 + +Create dependencies (Role, Group, Domain) and a RoleAssignment that assigns a role to a group on a domain. + +Verify that the observed state corresponds to the spec and the role assignment exists in OpenStack. + +## Step 01 + +Delete the RoleAssignment and verify it's removed from OpenStack. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-assert.yaml new file mode 100644 index 000000000..680b4e462 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-assert.yaml @@ -0,0 +1,75 @@ +--- +# Assert Role is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-gp-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert Group is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Group +metadata: + name: roleassignment-gp-test-group +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert Project is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-gp-test-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert RoleAssignment is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-group-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Validate RoleAssignment status fields +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-group-project + ref: roleassignment +assertAll: + # Verify status.id is NOT set (role assignments use component-based identification) + - celExpr: "!has(roleassignment.status.id) || roleassignment.status.id == ''" + # Verify all component IDs are populated in status.resource + - celExpr: "roleassignment.status.resource.roleID != ''" + - celExpr: "roleassignment.status.resource.groupID != ''" + - celExpr: "roleassignment.status.resource.projectID != ''" + # Verify user and domain are not set (since we used group and project) + - celExpr: "!has(roleassignment.status.resource.userID) || roleassignment.status.resource.userID == ''" + - celExpr: "!has(roleassignment.status.resource.domainID) || roleassignment.status.resource.domainID == ''" diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-create-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-create-resource.yaml new file mode 100644 index 000000000..229f73ac2 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-create-resource.yaml @@ -0,0 +1,54 @@ +--- +# Create a test role +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-gp-test-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-gp-test-role +--- +# Create a test group +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Group +metadata: + name: roleassignment-gp-test-group +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-gp-test-group +--- +# Create a test project +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-gp-test-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-gp-test-project +--- +# Create role assignment (group on project) +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-group-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-gp-test-role + groupRef: roleassignment-gp-test-group + projectRef: roleassignment-gp-test-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-project/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/01-assert.yaml new file mode 100644 index 000000000..774133d60 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/01-assert.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Verify RoleAssignment is deleted +- script: "! kubectl get roleassignment roleassignment-create-group-project --namespace $NAMESPACE" + skipLogOutput: true +--- +# Verify dependencies still exist (deletion guard should keep them) +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-gp-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Group +metadata: + name: roleassignment-gp-test-group +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-gp-test-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-project/01-delete-roleassignment.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/01-delete-roleassignment.yaml new file mode 100644 index 000000000..3e76e9a0f --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/01-delete-roleassignment.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-group-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-group-project/README.md b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/README.md new file mode 100644 index 000000000..5ea31a789 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-group-project/README.md @@ -0,0 +1,15 @@ +# Create a RoleAssignment for Group on Project + +## Step 00 + +Create dependencies (Role, Group, Project) and a RoleAssignment that assigns a role to a group on a project. + +Verify that the observed state corresponds to the spec and the role assignment exists in OpenStack. + +## Step 01 + +Delete the RoleAssignment and verify it's removed from OpenStack. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-assert.yaml new file mode 100644 index 000000000..9907fe691 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-assert.yaml @@ -0,0 +1,75 @@ +--- +# Assert Role is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-ud-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert User is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-ud-test-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert Domain is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-ud-test-domain +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert RoleAssignment is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-user-domain +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Validate RoleAssignment status fields +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-user-domain + ref: roleassignment +assertAll: + # Verify status.id is NOT set (role assignments use component-based identification) + - celExpr: "!has(roleassignment.status.id) || roleassignment.status.id == ''" + # Verify all component IDs are populated in status.resource + - celExpr: "roleassignment.status.resource.roleID != ''" + - celExpr: "roleassignment.status.resource.userID != ''" + - celExpr: "roleassignment.status.resource.domainID != ''" + # Verify group and project are not set (since we used user and domain) + - celExpr: "!has(roleassignment.status.resource.groupID) || roleassignment.status.resource.groupID == ''" + - celExpr: "!has(roleassignment.status.resource.projectID) || roleassignment.status.resource.projectID == ''" diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-create-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-create-resource.yaml new file mode 100644 index 000000000..844b43af0 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-create-resource.yaml @@ -0,0 +1,54 @@ +--- +# Create a test role +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-ud-test-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-ud-test-role +--- +# Create a test user +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-ud-test-user +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-ud-test-user +--- +# Create a test domain +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-ud-test-domain +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-ud-test-domain +--- +# Create the role assignment +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-user-domain +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-ud-test-role + userRef: roleassignment-ud-test-user + domainRef: roleassignment-ud-test-domain diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/01-assert.yaml new file mode 100644 index 000000000..49610f398 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/01-assert.yaml @@ -0,0 +1,9 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: roleassignment-ud-test-domain + ref: domain +assertAll: + - celExpr: "domain.status.resource.enabled == false" \ No newline at end of file diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/01-disable-domain.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/01-disable-domain.yaml new file mode 100644 index 000000000..09053901a --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/01-disable-domain.yaml @@ -0,0 +1,7 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-ud-test-domain +spec: + resource: + enabled: false \ No newline at end of file diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/02-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/02-assert.yaml new file mode 100644 index 000000000..fee740b41 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/02-assert.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Verify RoleAssignment is deleted +- script: "! kubectl get roleassignment roleassignment-create-user-domain --namespace $NAMESPACE" + skipLogOutput: true +--- +# Verify dependencies still exist (deletion guard should keep them) +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-ud-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-ud-test-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: roleassignment-ud-test-domain +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/02-delete-roleassignment.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/02-delete-roleassignment.yaml new file mode 100644 index 000000000..d2ad8ee20 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/02-delete-roleassignment.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-user-domain diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/README.md b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/README.md new file mode 100644 index 000000000..d74af937a --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-domain/README.md @@ -0,0 +1,15 @@ +# Create a RoleAssignment for User on Domain + +## Step 00 + +Create dependencies (Role, User, Domain) and a RoleAssignment that assigns a role to a user on a domain. + +Verify that the observed state corresponds to the spec and the role assignment exists in OpenStack. + +## Step 01 + +Delete the RoleAssignment and verify it's removed from OpenStack. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-assert.yaml new file mode 100644 index 000000000..7a56b4d4c --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-assert.yaml @@ -0,0 +1,75 @@ +--- +# Assert Role is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-up-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert User is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-up-test-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert Project is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-up-test-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Assert RoleAssignment is available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-user-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Validate RoleAssignment status fields +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-user-project + ref: roleassignment +assertAll: + # Verify status.id is NOT set (role assignments use component-based identification) + - celExpr: "!has(roleassignment.status.id) || roleassignment.status.id == ''" + # Verify all component IDs are populated in status.resource + - celExpr: "roleassignment.status.resource.roleID != ''" + - celExpr: "roleassignment.status.resource.userID != ''" + - celExpr: "roleassignment.status.resource.projectID != ''" + # Verify group and domain are not set (since we used user and project) + - celExpr: "!has(roleassignment.status.resource.groupID) || roleassignment.status.resource.groupID == ''" + - celExpr: "!has(roleassignment.status.resource.domainID) || roleassignment.status.resource.domainID == ''" diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-create-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-create-resource.yaml new file mode 100644 index 000000000..dbc89aed6 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-create-resource.yaml @@ -0,0 +1,54 @@ +--- +# Create a test role +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-up-test-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-up-test-role +--- +# Create a test user +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-up-test-user +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-up-test-user +--- +# Create a test project +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-up-test-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-up-test-project +--- +# Create the role assignment +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-create-user-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-up-test-role + userRef: roleassignment-up-test-user + projectRef: roleassignment-up-test-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-project/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/01-assert.yaml new file mode 100644 index 000000000..607c22ab4 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/01-assert.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Verify RoleAssignment is deleted +- script: "! kubectl get roleassignment roleassignment-create-user-project --namespace $NAMESPACE" + skipLogOutput: true +--- +# Verify dependencies still exist (deletion guard should keep them) +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-up-test-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-up-test-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-up-test-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-project/01-delete-roleassignment.yaml b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/01-delete-roleassignment.yaml new file mode 100644 index 000000000..9b20de4ef --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/01-delete-roleassignment.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-create-user-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-create-user-project/README.md b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/README.md new file mode 100644 index 000000000..3b92d0da2 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-create-user-project/README.md @@ -0,0 +1,15 @@ +# Create a RoleAssignment with minimum options + +## Step 00 + +Create dependencies (Role, User, Project) and a minimal RoleAssignment that assigns a role to a user on a project. + +Verify that the observed state corresponds to the spec and the role assignment exists in OpenStack. + +## Step 01 + +Delete the RoleAssignment and verify it's removed from OpenStack. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/00-assert.yaml new file mode 100644 index 000000000..448d7ee63 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/00-assert.yaml @@ -0,0 +1,13 @@ +--- +# Verify RoleAssignment is Progressing (waiting for dependencies) +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-dependency +status: + conditions: + - type: Available + status: "False" + - type: Progressing + status: "True" + reason: Progressing diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..412216039 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,15 @@ +--- +# Create RoleAssignment with missing dependencies +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-dep-role + userRef: roleassignment-dep-user + projectRef: roleassignment-dep-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/00-secret.yaml new file mode 100644 index 000000000..f0fb63e85 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/00-secret.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/01-assert.yaml new file mode 100644 index 000000000..7ddf9a725 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/01-assert.yaml @@ -0,0 +1,76 @@ +--- +# Verify dependencies are Available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-dep-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-dep-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-dep-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Verify RoleAssignment is now Available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-dependency +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +# Verify deletion guard finalizers are set on dependencies +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Role + name: roleassignment-dep-role + ref: role + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: roleassignment-dep-user + ref: user + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: roleassignment-dep-project + ref: project +assertAll: + # Check that deletion guard finalizers are present + - celExpr: "role.metadata.finalizers.exists(f, f.startsWith('openstack.k-orc.cloud/roleassignment'))" + - celExpr: "user.metadata.finalizers.exists(f, f.startsWith('openstack.k-orc.cloud/roleassignment'))" + - celExpr: "project.metadata.finalizers.exists(f, f.startsWith('openstack.k-orc.cloud/roleassignment'))" diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/01-create-dependencies.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..a113632a8 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/01-create-dependencies.yaml @@ -0,0 +1,37 @@ +--- +# Create the dependencies +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-dep-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-dep-role +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-dep-user +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-dep-user +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-dep-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-dep-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/02-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/02-assert.yaml new file mode 100644 index 000000000..3473f0837 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/02-assert.yaml @@ -0,0 +1,26 @@ +--- +# Verify Project still exists (deletion blocked by finalizer) +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: roleassignment-dep-project + ref: project +assertAll: + - celExpr: "project.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/roleassignment' in project.metadata.finalizers" +--- +# Verify RoleAssignment still Available +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-dependency +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/02-delete-dependencies.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/02-delete-dependencies.yaml new file mode 100644 index 000000000..3ea65dfe7 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/02-delete-dependencies.yaml @@ -0,0 +1,6 @@ +--- +# Try to delete a dependency (should be blocked by finalizer) +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl delete project roleassignment-dep-project --namespace $NAMESPACE --wait=false diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/03-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/03-assert.yaml new file mode 100644 index 000000000..1a99c8e08 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/03-assert.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Verify RoleAssignment is deleted +- script: "! kubectl get roleassignment roleassignment-dependency --namespace $NAMESPACE" + skipLogOutput: true +# Verify Project can now be deleted (finalizer removed) +- script: "! kubectl get project roleassignment-dep-project --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/03-delete-resources.yaml b/internal/controllers/roleassignment/tests/roleassignment-dependency/03-delete-resources.yaml new file mode 100644 index 000000000..cc50ec3db --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/03-delete-resources.yaml @@ -0,0 +1,8 @@ +--- +# Delete RoleAssignment first +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-dependency diff --git a/internal/controllers/roleassignment/tests/roleassignment-dependency/README.md b/internal/controllers/roleassignment/tests/roleassignment-dependency/README.md new file mode 100644 index 000000000..49d537638 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-dependency/README.md @@ -0,0 +1,23 @@ +# Test RoleAssignment dependency handling + +## Step 00 + +Create a RoleAssignment that references Role, User, and Project that don't exist yet. +Verify that it enters Progressing state waiting for dependencies. + +## Step 01 + +Create the dependencies and verify the RoleAssignment becomes Available. + +## Step 02 + +Try to delete a dependency (Project) while it's still referenced by the RoleAssignment. +Verify the deletion is blocked by the finalizer. + +## Step 03 + +Delete the RoleAssignment first, then verify dependencies can be deleted. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependencies diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-assert.yaml new file mode 100644 index 000000000..c90c27041 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-assert.yaml @@ -0,0 +1,43 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-import-dep-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-import-dep-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-dep +status: + conditions: + - type: Available + message: |- + Waiting for Role/roleassignment-import-dep-role to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Role/roleassignment-import-dep-role to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-import-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-import-resource.yaml new file mode 100644 index 000000000..f795c68ae --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-import-resource.yaml @@ -0,0 +1,56 @@ +--- +# Unmanaged Role that imports by name. No matching OpenStack role exists yet, +# so this will stay in Progressing state. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-dep-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: roleassignment-import-dep-ext-role +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-import-dep-user +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-dep-user +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-import-dep-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-dep-project +--- +# Import RoleAssignment referencing the unmanaged Role. Since the Role is not +# yet available, this should wait on the dependency. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-dep +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + roleRef: roleassignment-import-dep-role + userRef: roleassignment-import-dep-user + projectRef: roleassignment-import-dep-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/01-assert.yaml new file mode 100644 index 000000000..105272ace --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/01-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-dep-trap +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-dep +status: + conditions: + - type: Available + message: |- + Waiting for Role/roleassignment-import-dep-role to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Role/roleassignment-import-dep-role to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/01-create-trap-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/01-create-trap-resource.yaml new file mode 100644 index 000000000..7b4db41fa --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/01-create-trap-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-dep-trap-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-dep-trap-role +--- +# This role assignment uses a different role but the same user and project. +# It should not be picked by the import filter. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-dep-trap +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-import-dep-trap-role + userRef: roleassignment-import-dep-user + projectRef: roleassignment-import-dep-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/02-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/02-assert.yaml new file mode 100644 index 000000000..4e44d0fa3 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/02-assert.yaml @@ -0,0 +1,39 @@ +--- +# Verify the imported role assignment matches the created one +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-import-dep + ref: importedRA + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-import-dep-external + ref: externalRA + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Role + name: roleassignment-import-dep-role + ref: role +assertAll: + # Import should have same component IDs as external + - celExpr: "importedRA.status.resource.roleID == externalRA.status.resource.roleID" + - celExpr: "importedRA.status.resource.userID == externalRA.status.resource.userID" + - celExpr: "importedRA.status.resource.projectID == externalRA.status.resource.projectID" + # The roleID should match the unmanaged Role's imported status.id + - celExpr: "importedRA.status.resource.roleID == role.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-dep +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/02-create-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/02-create-resource.yaml new file mode 100644 index 000000000..1165c7af5 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/02-create-resource.yaml @@ -0,0 +1,29 @@ +--- +# Create the managed Role that satisfies the unmanaged Role's import filter. +# The unmanaged Role imports by filter name: roleassignment-import-dep-ext-role +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-dep-ext-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-dep-ext-role +--- +# Create the role assignment matching the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-dep-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-import-dep-ext-role + userRef: roleassignment-import-dep-user + projectRef: roleassignment-import-dep-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/03-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/03-assert.yaml new file mode 100644 index 000000000..396d7efe5 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/03-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get role.openstack.k-orc.cloud roleassignment-import-dep-role --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/03-delete-import-dependencies.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/03-delete-import-dependencies.yaml new file mode 100644 index 000000000..e1b01ffab --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/03-delete-import-dependencies.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We should be able to delete the import dependencies + - command: kubectl delete role.openstack.k-orc.cloud roleassignment-import-dep-role + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/04-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/04-assert.yaml new file mode 100644 index 000000000..9ac45ea07 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/04-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get roleassignment roleassignment-import-dep --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/04-delete-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/04-delete-resource.yaml new file mode 100644 index 000000000..4c0c62425 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/04-delete-resource.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-import-dep diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-dependency/README.md b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/README.md new file mode 100644 index 000000000..b804056ba --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-dependency/README.md @@ -0,0 +1,32 @@ +# Check dependency handling for imported RoleAssignment + +## Step 00 + +Create an unmanaged Role importing by filter (name that doesn't exist yet), +managed User and Project dependencies, and an unmanaged RoleAssignment +importing by filter with roleRef pointing to the unmanaged Role. +Verify the RoleAssignment is waiting for the Role dependency to be ready. + +## Step 01 + +Create a trap RoleAssignment with a different role but the same user and +project, and verify that it is not being imported. + +## Step 02 + +Create a managed Role matching the unmanaged Role's import filter and a +managed RoleAssignment matching the import filter. Verify the imported +RoleAssignment is available with correct component IDs. + +## Step 03 + +Delete the import dependency (the unmanaged Role) and verify ORC does not +prevent deletion. Import dependencies should not have deletion guards. + +## Step 04 + +Delete the imported RoleAssignment and verify it's gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-dependency diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-error/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-error/00-assert.yaml new file mode 100644 index 000000000..44cbe53fb --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-error/00-assert.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-err-role-1 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-err-role-2 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-import-err-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-import-err-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-err-1 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-err-2 +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-error/00-create-resources.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-error/00-create-resources.yaml new file mode 100644 index 000000000..f5f499b58 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-error/00-create-resources.yaml @@ -0,0 +1,76 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-err-role-1 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-err-role-1 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-err-role-2 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-err-role-2 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-import-err-user +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-err-user +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-import-err-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-err-project +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-err-1 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-import-err-role-1 + userRef: roleassignment-import-err-user + projectRef: roleassignment-import-err-project +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-err-2 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-import-err-role-2 + userRef: roleassignment-import-err-user + projectRef: roleassignment-import-err-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-error/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-error/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-error/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-error/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-error/01-assert.yaml new file mode 100644 index 000000000..1f7e3a893 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-error/01-import-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import-error/01-import-resource.yaml new file mode 100644 index 000000000..030399b68 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-error/01-import-resource.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-error +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + userRef: roleassignment-import-err-user + projectRef: roleassignment-import-err-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import-error/README.md b/internal/controllers/roleassignment/tests/roleassignment-import-error/README.md new file mode 100644 index 000000000..ffe332e6d --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import-error/README.md @@ -0,0 +1,17 @@ +# Import RoleAssignment Error + +## Step 00 + +Create dependencies (User, two Roles, a Project) as managed resources, and +two managed RoleAssignments assigning each role to the same user on the same +project. + +## Step 01 + +Import an unmanaged RoleAssignment using a filter that specifies only userRef +and projectRef. Both role assignments match the filter, causing a terminal +error because more than one matching resource was found. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/00-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import/00-assert.yaml new file mode 100644 index 000000000..175a5e837 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/00-assert.yaml @@ -0,0 +1,54 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-role +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-import-user +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-import-project +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/00-import-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import/00-import-resource.yaml new file mode 100644 index 000000000..e3e0c8df5 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/00-import-resource.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-role +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: roleassignment-import-user +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-user +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: roleassignment-import-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-project +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + roleRef: roleassignment-import-role + userRef: roleassignment-import-user + projectRef: roleassignment-import-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/00-secret.yaml b/internal/controllers/roleassignment/tests/roleassignment-import/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/01-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import/01-assert.yaml new file mode 100644 index 000000000..02fb6038b --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/01-assert.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-trap +status: + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/01-create-trap-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..6bc4c7745 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/01-create-trap-resource.yaml @@ -0,0 +1,29 @@ +--- +# Create a different role to use in the trap +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Role +metadata: + name: roleassignment-import-trap-role +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: roleassignment-import-trap-role +--- +# This role assignment uses a different role but the same user and project. +# It should not be picked by the import filter which specifies a different roleRef. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-trap +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-import-trap-role + userRef: roleassignment-import-user + projectRef: roleassignment-import-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/02-assert.yaml b/internal/controllers/roleassignment/tests/roleassignment-import/02-assert.yaml new file mode 100644 index 000000000..9552fa89e --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/02-assert.yaml @@ -0,0 +1,39 @@ +--- +# Verify the imported role assignment matches the created one +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-import + ref: importedRA + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-import-external + ref: externalRA + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RoleAssignment + name: roleassignment-import-trap + ref: trapRA +assertAll: + # Import should have same component IDs as external + - celExpr: "importedRA.status.resource.roleID == externalRA.status.resource.roleID" + - celExpr: "importedRA.status.resource.userID == externalRA.status.resource.userID" + - celExpr: "importedRA.status.resource.projectID == externalRA.status.resource.projectID" + # Import should not have picked the trap (different role ID) + - celExpr: "importedRA.status.resource.roleID != trapRA.status.resource.roleID" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/02-create-resource.yaml b/internal/controllers/roleassignment/tests/roleassignment-import/02-create-resource.yaml new file mode 100644 index 000000000..e01728436 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/02-create-resource.yaml @@ -0,0 +1,15 @@ +--- +# Create the role assignment matching the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RoleAssignment +metadata: + name: roleassignment-import-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + roleRef: roleassignment-import-role + userRef: roleassignment-import-user + projectRef: roleassignment-import-project diff --git a/internal/controllers/roleassignment/tests/roleassignment-import/README.md b/internal/controllers/roleassignment/tests/roleassignment-import/README.md new file mode 100644 index 000000000..ac505ff33 --- /dev/null +++ b/internal/controllers/roleassignment/tests/roleassignment-import/README.md @@ -0,0 +1,23 @@ +# Import RoleAssignment + +## Step 00 + +Create dependencies (Role, User, Project) as managed resources, and an +unmanaged RoleAssignment importing by filter that references all three. +Verify that the import RoleAssignment is waiting for the external resource +to be created in OpenStack. + +## Step 01 + +Create a trap RoleAssignment using a different role but the same user and +project, and verify that it is not being imported by the filter. + +## Step 02 + +Create a managed RoleAssignment matching the import filter and verify that +the imported RoleAssignment picks it up with the correct component IDs. +Also verify that the imported RoleAssignment didn't pick the trap. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import diff --git a/internal/controllers/roleassignment/zz_generated.adapter.go b/internal/controllers/roleassignment/zz_generated.adapter.go new file mode 100644 index 000000000..4247adea2 --- /dev/null +++ b/internal/controllers/roleassignment/zz_generated.adapter.go @@ -0,0 +1,85 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package roleassignment + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.RoleAssignment + orcObjectListT = orcv1alpha1.RoleAssignmentList + resourceSpecT = orcv1alpha1.RoleAssignmentResourceSpec + filterT = orcv1alpha1.RoleAssignmentFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = roleassignmentAdapter +) + +type roleassignmentAdapter struct { + *orcv1alpha1.RoleAssignment +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.RoleAssignment +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return nil +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + return nil +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} diff --git a/internal/controllers/roleassignment/zz_generated.controller.go b/internal/controllers/roleassignment/zz_generated.controller.go new file mode 100644 index 000000000..469e96460 --- /dev/null +++ b/internal/controllers/roleassignment/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package roleassignment + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/controllers/router/actuator.go b/internal/controllers/router/actuator.go index 04c1d491b..6369f4d9c 100644 --- a/internal/controllers/router/actuator.go +++ b/internal/controllers/router/actuator.go @@ -18,12 +18,10 @@ package router import ( "context" - "fmt" "iter" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -33,6 +31,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" osclients "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" ) @@ -49,15 +48,11 @@ type ( ) type routerActuator struct { - osClient osclients.NetworkClient -} - -type routerCreateActuator struct { - routerActuator + osClient osclients.NetworkClient k8sClient client.Client } -var _ createResourceActuator = routerCreateActuator{} +var _ createResourceActuator = routerActuator{} var _ deleteResourceActuator = routerActuator{} func (routerActuator) GetResourceID(osResource *osResourceT) string { @@ -73,35 +68,44 @@ func (actuator routerActuator) GetOSResourceByID(ctx context.Context, id string) } func (actuator routerActuator) ListOSResourcesForAdoption(ctx context.Context, obj *orcv1alpha1.Router) (routerIterator, bool) { - if obj.Spec.Resource == nil { + resource := obj.Spec.Resource + if resource == nil { return nil, false } - listOpts := routers.ListOpts{Name: getResourceName(obj)} + // Resolve the project ID from ProjectRef if set. Without the project + // ID, adoption with admin-scoped credentials could match a router + // in the wrong project. + var projectID string + if resource.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + + listOpts := routers.ListOpts{ + Name: getResourceName(obj), + ProjectID: projectID, + Distributed: resource.Distributed, + } return actuator.osClient.ListRouter(ctx, listOpts), true } -func (actuator routerCreateActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { +func (actuator routerActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { var reconcileStatus progress.ReconcileStatus - project := &orcv1alpha1.Project{} - if filter.ProjectRef != nil { - projectKey := client.ObjectKey{Name: string(*filter.ProjectRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, projectKey, project); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching project %s: %w", projectKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(project) || project.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnReady)) - } - } - } + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -120,7 +124,7 @@ func (actuator routerCreateActuator) ListOSResourcesForImport(ctx context.Contex return actuator.osClient.ListRouter(ctx, listOpts), nil } -func (actuator routerCreateActuator) CreateResource(ctx context.Context, obj *orcv1alpha1.Router) (*osResourceT, progress.ReconcileStatus) { +func (actuator routerActuator) CreateResource(ctx context.Context, obj *orcv1alpha1.Router) (*osResourceT, progress.ReconcileStatus) { resource := obj.Spec.Resource if resource == nil { // Should have been caught by API validation @@ -135,9 +139,7 @@ func (actuator routerCreateActuator) CreateResource(ctx context.Context, obj *or var externalGW *orcv1alpha1.Network // Fetch dependencies and ensure they have our finalizer externalGW, reconcileStatus = externalGWDep.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Network) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) if externalGW != nil { gatewayInfo.NetworkID = ptr.Deref(externalGW.Status.ID, "") @@ -147,9 +149,7 @@ func (actuator routerCreateActuator) CreateResource(ctx context.Context, obj *or var projectID string if resource.ProjectRef != nil { project, projectDepRS := projectDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Project) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) if project != nil { @@ -179,12 +179,10 @@ func (actuator routerCreateActuator) CreateResource(ctx context.Context, obj *or osResource, err := actuator.osClient.CreateRouter(ctx, &createOpts) - // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } return nil, progress.WrapError(err) } return osResource, nil @@ -222,10 +220,10 @@ func (actuator routerActuator) updateResource(ctx context.Context, obj orcObject _, err = actuator.osClient.UpdateRouter(ctx, osResource.ID, updateOpts) - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } @@ -286,7 +284,7 @@ func (routerHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { } func (routerHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { - return newCreateActuator(ctx, orcObject, controller) + return newActuator(ctx, orcObject, controller) } func (routerHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { @@ -312,18 +310,7 @@ func newActuator(ctx context.Context, orcObject *orcv1alpha1.Router, controller } return routerActuator{ - osClient: osClient, - }, nil -} - -func newCreateActuator(ctx context.Context, orcObject *orcv1alpha1.Router, controller interfaces.ResourceController) (routerCreateActuator, progress.ReconcileStatus) { - routerActuator, reconcileStatus := newActuator(ctx, orcObject, controller) - if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { - return routerCreateActuator{}, reconcileStatus - } - - return routerCreateActuator{ - routerActuator: routerActuator, - k8sClient: controller.GetK8sClient(), + osClient: osClient, + k8sClient: controller.GetK8sClient(), }, nil } diff --git a/internal/controllers/router/controller.go b/internal/controllers/router/controller.go index 3b11b3192..2509bd4de 100644 --- a/internal/controllers/router/controller.go +++ b/internal/controllers/router/controller.go @@ -19,6 +19,7 @@ package router import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -38,17 +39,22 @@ import ( // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=routers/status,verbs=get;update;patch type routerReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return routerReconcilerConstructor{scopeFactory: scopeFactory} + return &routerReconcilerConstructor{scopeFactory: scopeFactory} } func (routerReconcilerConstructor) GetName() string { return controllerName } +func (c *routerReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + const controllerName = "router" var ( @@ -95,7 +101,7 @@ var ( ) // SetupWithManager sets up the controller with the Manager. -func (c routerReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *routerReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := mgr.GetLogger().WithValues("controller", controllerName) k8sClient := mgr.GetClient() @@ -138,6 +144,6 @@ func (c routerReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c return err } - r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, routerHelperFactory{}, routerStatusWriter{}) + r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, routerHelperFactory{}, routerStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/router/suite_test.go b/internal/controllers/router/suite_test.go index 02433215f..c04e852fe 100644 --- a/internal/controllers/router/suite_test.go +++ b/internal/controllers/router/suite_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + utilrand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -82,7 +83,7 @@ var _ = Describe("EnvTest sanity check", func() { It("should be able to create a namespace", func() { ctx := context.TODO() namespace := &corev1.Namespace{} - namespace.SetGenerateName("test-") + namespace.SetName("test-" + utilrand.String(10)) // Create the namespace Expect(k8sClient.Create(ctx, namespace)).To(Succeed(), "create namespace") diff --git a/internal/controllers/router/zz_generated.adapter.go b/internal/controllers/router/zz_generated.adapter.go index 27f6b7339..fedcdd75a 100644 --- a/internal/controllers/router/zz_generated.adapter.go +++ b/internal/controllers/router/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package router import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/router/zz_generated.controller.go b/internal/controllers/router/zz_generated.controller.go index 255858fc5..71e247334 100644 --- a/internal/controllers/router/zz_generated.controller.go +++ b/internal/controllers/router/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/routerinterface/controller.go b/internal/controllers/routerinterface/controller.go index b25cdacf9..62c066d92 100644 --- a/internal/controllers/routerinterface/controller.go +++ b/internal/controllers/routerinterface/controller.go @@ -45,21 +45,27 @@ const ( ) type routerInterfaceReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return routerInterfaceReconcilerConstructor{scopeFactory: scopeFactory} + return &routerInterfaceReconcilerConstructor{scopeFactory: scopeFactory} } func (routerInterfaceReconcilerConstructor) GetName() string { return controllerName } +func (c *routerInterfaceReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // orcRouterInterfaceReconciler reconciles an ORC Subnet. type orcRouterInterfaceReconciler struct { - client client.Client - scopeFactory scope.Factory + client client.Client + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } const controllerName = "routerinterface" @@ -89,7 +95,7 @@ var ( ) // SetupWithManager sets up the controller with the Manager. -func (c routerInterfaceReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *routerInterfaceReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := mgr.GetLogger().WithValues("controller", controllerName) if err := errors.Join( @@ -105,8 +111,9 @@ func (c routerInterfaceReconcilerConstructor) SetupWithManager(ctx context.Conte // dependencies because it reconciles Routers, not RouterInterfaces. reconciler := orcRouterInterfaceReconciler{ - client: k8sClient, - scopeFactory: c.scopeFactory, + client: k8sClient, + scopeFactory: c.scopeFactory, + defaultResyncPeriod: c.defaultResyncPeriod, } return ctrl.NewControllerManagedBy(mgr). For(&orcv1alpha1.Router{}, builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Router{}))). diff --git a/internal/controllers/routerinterface/reconcile.go b/internal/controllers/routerinterface/reconcile.go index 2aba2f001..61a950410 100644 --- a/internal/controllers/routerinterface/reconcile.go +++ b/internal/controllers/routerinterface/reconcile.go @@ -31,6 +31,8 @@ import ( orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/resync" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" osclients "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" @@ -48,7 +50,38 @@ func (r *orcRouterInterfaceReconciler) Reconcile(ctx context.Context, req ctrl.R router := &orcv1alpha1.Router{} if err := r.client.Get(ctx, req.NamespacedName, router); err != nil { if apierrors.IsNotFound(err) { - return ctrl.Result{}, nil + // The router does not exist (yet). We still need to update the status + // on all RouterInterfaces that are associated with that router + + // Creating a dummy router struct with namespace and name will be enough to + // retrieve all defined RouterInterfaces for that to-be-created router + router.Name = req.Name + router.Namespace = req.Namespace + routerInterfaces, err := routerDependency.GetObjectsForDependency(ctx, r.client, router) + + if err != nil { + return ctrl.Result{}, fmt.Errorf("fetching router interfaces: %w", err) + } + + if len(routerInterfaces) == 0 { + return ctrl.Result{}, nil + } + + var osResource *osclients.PortExt + + var reconcileStatus progress.ReconcileStatus + for i := range routerInterfaces { + routerInterface := &routerInterfaces[i] + log = log.WithValues("name", routerInterface.Name) + + var ifReconcileStatus progress.ReconcileStatus + ifReconcileStatus = progress.WaitingOnObject("Router", req.Name, progress.WaitingOnCreation) + ifReconcileStatus = ifReconcileStatus.WithReconcileStatus(r.updateStatus(ctx, routerInterface, osResource, ifReconcileStatus)) + + reconcileStatus = reconcileStatus.WithReconcileStatus(ifReconcileStatus) + } + + return reconcileStatus.Return(log) } return ctrl.Result{}, err } @@ -70,6 +103,32 @@ func (r *orcRouterInterfaceReconciler) Reconcile(ctx context.Context, req ctrl.R return ctrl.Result{}, nil } + var reconcileStatus progress.ReconcileStatus + routerInterfacesToReconcile := make([]*orcv1alpha1.RouterInterface, 0, len(routerInterfaces)) + for i := range routerInterfaces { + routerInterface := &routerInterfaces[i] + + if !routerInterface.GetDeletionTimestamp().IsZero() { + routerInterfacesToReconcile = append(routerInterfacesToReconcile, routerInterface) + continue + } + + effectiveResyncPeriod := resync.DetermineResyncPeriod(routerInterface.Spec.ResyncPeriod, r.defaultResyncPeriod) + if !reconciler.ShouldReconcile(routerInterface, routerInterface.Status.LastSyncTime, effectiveResyncPeriod) { + if remaining := resync.RemainingUntilNextSync(routerInterface.Status.LastSyncTime, effectiveResyncPeriod); remaining > 0 { + reconcileStatus = reconcileStatus.WithRequeue(remaining) + } + continue + } + + routerInterfacesToReconcile = append(routerInterfacesToReconcile, routerInterface) + } + + if len(routerInterfacesToReconcile) == 0 { + log.V(logging.Verbose).Info("Router interfaces are up to date: not reconciling") + return reconcileStatus.Return(log) + } + // If there are interfaces, the router should have our finalizer if err := dependency.EnsureFinalizer(ctx, r.client, router, finalizer, fieldOwner); err != nil { return ctrl.Result{}, fmt.Errorf("writing finalizer: %w", err) @@ -103,9 +162,7 @@ func (r *orcRouterInterfaceReconciler) Reconcile(ctx context.Context, req ctrl.R } } - var reconcileStatus progress.ReconcileStatus - for i := range routerInterfaces { - routerInterface := &routerInterfaces[i] + for _, routerInterface := range routerInterfacesToReconcile { log = log.WithValues("name", routerInterface.Name) var ifReconcileStatus progress.ReconcileStatus diff --git a/internal/controllers/routerinterface/status.go b/internal/controllers/routerinterface/status.go index 6c3ea10e8..971168908 100644 --- a/internal/controllers/routerinterface/status.go +++ b/internal/controllers/routerinterface/status.go @@ -64,6 +64,9 @@ func createStatusUpdate(orcObject *orcv1alpha1.RouterInterface, port *osclients. isAvailable, statusReconcileStatus := getStatusSummary(port) reconcileStatus = reconcileStatus.WithReconcileStatus(statusReconcileStatus) status.SetCommonConditions(orcObject, applyConfigStatus, isAvailable, reconcileStatus, now) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); !needsReschedule { + applyConfigStatus.WithLastSyncTime(now) + } return applyConfig, reconcileStatus } diff --git a/internal/controllers/routerinterface/suite_test.go b/internal/controllers/routerinterface/suite_test.go index 8c93ac434..3bae8c80e 100644 --- a/internal/controllers/routerinterface/suite_test.go +++ b/internal/controllers/routerinterface/suite_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + utilrand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -82,7 +83,7 @@ var _ = Describe("EnvTest sanity check", func() { It("should be able to create a namespace", func() { ctx := context.TODO() namespace := &corev1.Namespace{} - namespace.SetGenerateName("test-") + namespace.SetName("test-" + utilrand.String(10)) // Create the namespace Expect(k8sClient.Create(ctx, namespace)).To(Succeed(), "create namespace") diff --git a/internal/controllers/routerinterface/tests/routerinterface-dependency/00-assert.yaml b/internal/controllers/routerinterface/tests/routerinterface-dependency/00-assert.yaml index 06aed6c4f..3a1047ca5 100644 --- a/internal/controllers/routerinterface/tests/routerinterface-dependency/00-assert.yaml +++ b/internal/controllers/routerinterface/tests/routerinterface-dependency/00-assert.yaml @@ -3,17 +3,16 @@ apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RouterInterface metadata: name: routerinterface-dependency-no-router -# FIXME: https://github.com/k-orc/openstack-resource-controller/issues/314 -# status: -# conditions: -# - type: Available -# message: Waiting for Router/routerinterface-dependency-pending to be created -# status: "False" -# reason: Progressing -# - type: Progressing -# message: Waiting for Router/routerinterface-dependency-pending to be created -# status: "True" -# reason: Progressing +status: + conditions: + - type: Available + message: Waiting for Router/routerinterface-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Router/routerinterface-dependency-pending to be created + status: "True" + reason: Progressing --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RouterInterface diff --git a/internal/controllers/securitygroup/actuator.go b/internal/controllers/securitygroup/actuator.go index b7165e595..7830ab3ff 100644 --- a/internal/controllers/securitygroup/actuator.go +++ b/internal/controllers/securitygroup/actuator.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "iter" + "time" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules" @@ -29,10 +30,10 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" osclients "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" "k8s.io/utils/set" ctrl "sigs.k8s.io/controller-runtime" @@ -50,6 +51,11 @@ type ( securityGroupIterator = iter.Seq2[*osResourceT, error] ) +const ( + // The frequency to poll when waiting for the resource to become available + securityGroupAvailablePollingPeriod = 15 * time.Second +) + type securityGroupActuator struct { osClient osclients.NetworkClient k8sClient client.Client @@ -71,35 +77,44 @@ func (actuator securityGroupActuator) GetOSResourceByID(ctx context.Context, id } func (actuator securityGroupActuator) ListOSResourcesForAdoption(ctx context.Context, obj *orcv1alpha1.SecurityGroup) (securityGroupIterator, bool) { - if obj.Spec.Resource == nil { + resource := obj.Spec.Resource + if resource == nil { return nil, false } - listOpts := groups.ListOpts{Name: getResourceName(obj)} + // Resolve the project ID from ProjectRef if set. Without the project + // ID, adoption with admin-scoped credentials could match a security + // group in the wrong project. + var projectID string + if resource.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + + listOpts := groups.ListOpts{ + Name: getResourceName(obj), + ProjectID: projectID, + Stateful: resource.Stateful, + } return actuator.osClient.ListSecGroup(ctx, listOpts), true } func (actuator securityGroupActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { var reconcileStatus progress.ReconcileStatus - project := &orcv1alpha1.Project{} - if filter.ProjectRef != nil { - projectKey := client.ObjectKey{Name: string(*filter.ProjectRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, projectKey, project); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching project %s: %w", projectKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(project) || project.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnReady)) - } - } - } + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -128,9 +143,7 @@ func (actuator securityGroupActuator) CreateResource(ctx context.Context, obj *o var projectID string if resource.ProjectRef != nil { project, reconcileStatus := projectDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Project) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -145,13 +158,10 @@ func (actuator securityGroupActuator) CreateResource(ctx context.Context, obj *o ProjectID: projectID, } - // FIXME(mandre) The security group inherits the default security group - // rules. This could be a problem when we implement `update` if ORC - // does not takes these rules into account. osResource, err := actuator.osClient.CreateSecGroup(ctx, &createOpts) if err != nil { - // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsConflict(err) { + // We should require the spec to be updated before retrying a create which returned a non-retryable error + if !orcerrors.IsRetryable(err) { err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) } return nil, progress.WrapError(err) @@ -199,10 +209,10 @@ func (actuator securityGroupActuator) updateResource(ctx context.Context, obj or _, err = actuator.osClient.UpdateSecGroup(ctx, osResource.ID, updateOpts) - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } @@ -288,9 +298,7 @@ func (actuator securityGroupActuator) updateRules(ctx context.Context, orcObject var projectID string if resource.ProjectRef != nil { project, reconcileStatus := projectDependency.GetDependency( - ctx, actuator.k8sClient, orcObject, func(dep *orcv1alpha1.Project) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, orcObject, orcv1alpha1.IsAvailable, ) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return reconcileStatus @@ -342,7 +350,7 @@ orcRules: if len(ruleCreateOpts) > 0 { if _, createErr := actuator.osClient.CreateSecGroupRules(ctx, ruleCreateOpts); createErr != nil { // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsRetryable(createErr) { + if !orcerrors.IsRetryable(createErr) { createErr = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+createErr.Error(), createErr) } else { createErr = fmt.Errorf("creating security group rules: %w", createErr) diff --git a/internal/controllers/securitygroup/controller.go b/internal/controllers/securitygroup/controller.go index 2e5d525e5..d52103ce5 100644 --- a/internal/controllers/securitygroup/controller.go +++ b/internal/controllers/securitygroup/controller.go @@ -19,6 +19,7 @@ package securitygroup import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -65,11 +66,12 @@ var ( ) type securitygroupReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return securitygroupReconcilerConstructor{ + return &securitygroupReconcilerConstructor{ scopeFactory: scopeFactory, } } @@ -78,8 +80,12 @@ func (securitygroupReconcilerConstructor) GetName() string { return controllerName } +func (c *securitygroupReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c securitygroupReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *securitygroupReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) k8sClient := mgr.GetClient() @@ -113,7 +119,7 @@ func (c securitygroupReconcilerConstructor) SetupWithManager(ctx context.Context return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, securityGroupHelperFactory{}, securityGroupStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, securityGroupHelperFactory{}, securityGroupStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/securitygroup/status.go b/internal/controllers/securitygroup/status.go index 94a83c8f7..90e172d45 100644 --- a/internal/controllers/securitygroup/status.go +++ b/internal/controllers/securitygroup/status.go @@ -45,7 +45,24 @@ func (securityGroupStatusWriter) ResourceAvailableStatus(orcObject orcObjectPT, } } - // SecurityGroup is available as soon as it exists + resourceSpec := orcObject.Spec.Resource + if resourceSpec != nil && resourceSpec.Rules != nil { + // Make sure specified security group rules exist in resource + + resourceStatus := orcObject.Status.Resource + if resourceStatus == nil || resourceStatus.Rules == nil { + return metav1.ConditionFalse, progress.WaitingOnOpenStack(progress.WaitingOnReady, securityGroupAvailablePollingPeriod) + } + + if len(resourceSpec.Rules) != len(resourceStatus.Rules) { + return metav1.ConditionFalse, progress.WaitingOnOpenStack(progress.WaitingOnReady, securityGroupAvailablePollingPeriod) + } + + if len(resourceSpec.Rules) != len(osResource.Rules) { + return metav1.ConditionFalse, progress.WaitingOnOpenStack(progress.WaitingOnReady, securityGroupAvailablePollingPeriod) + } + } + return metav1.ConditionTrue, nil } diff --git a/internal/controllers/securitygroup/zz_generated.adapter.go b/internal/controllers/securitygroup/zz_generated.adapter.go index eb98fad70..fda940c01 100644 --- a/internal/controllers/securitygroup/zz_generated.adapter.go +++ b/internal/controllers/securitygroup/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package securitygroup import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/securitygroup/zz_generated.controller.go b/internal/controllers/securitygroup/zz_generated.controller.go index d6a0449a7..e3477ad53 100644 --- a/internal/controllers/securitygroup/zz_generated.controller.go +++ b/internal/controllers/securitygroup/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/server/actuator.go b/internal/controllers/server/actuator.go index 6a2118695..873ef516d 100644 --- a/internal/controllers/server/actuator.go +++ b/internal/controllers/server/actuator.go @@ -18,6 +18,7 @@ package server import ( "context" + "encoding/json" "fmt" "iter" "maps" @@ -29,7 +30,6 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/volumeattach" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -39,6 +39,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" ) @@ -150,67 +151,96 @@ func (actuator serverActuator) ListOSResourcesForImport(ctx context.Context, obj return wrapServers(actuator.osClient.ListServers(ctx, listOpts)), nil } -// getDependencyHelper is a generic helper for fetching and validating dependencies -func getDependencyHelper[T client.Object]( - ctx context.Context, - k8sClient client.Client, - obj *orcv1alpha1.Server, - name string, - kind string, - isReady func(T) bool, - dep T, -) (T, progress.ReconcileStatus) { - objectKey := client.ObjectKey{Name: name, Namespace: obj.Namespace} - err := k8sClient.Get(ctx, objectKey, dep) - if apierrors.IsNotFound(err) { - return dep, progress.NewReconcileStatus().WaitingOnObject(kind, objectKey.Name, progress.WaitingOnCreation) - } else if err != nil { - return dep, progress.WrapError(fmt.Errorf("fetching %s %s: %w", kind, objectKey.Name, err)) - } else if !isReady(dep) { - return dep, progress.NewReconcileStatus().WaitingOnObject(kind, objectKey.Name, progress.WaitingOnReady) - } - return dep, progress.NewReconcileStatus() -} - -func (actuator serverActuator) getFlavorHelper(ctx context.Context, obj *orcv1alpha1.Server, resource *orcv1alpha1.ServerResourceSpec) (*orcv1alpha1.Flavor, progress.ReconcileStatus) { - return getDependencyHelper(ctx, actuator.k8sClient, obj, string(resource.FlavorRef), "Flavor", func(f *orcv1alpha1.Flavor) bool { - return orcv1alpha1.IsAvailable(f) && f.Status.ID != nil - }, &orcv1alpha1.Flavor{}) -} +func (actuator serverActuator) getSchedulerHints(ctx context.Context, obj *orcv1alpha1.Server, resource *orcv1alpha1.ServerResourceSpec) (servers.SchedulerHintOpts, progress.ReconcileStatus) { + hints := servers.SchedulerHintOpts{} -func (actuator serverActuator) getServerGroupHelper(ctx context.Context, obj *orcv1alpha1.Server, resource *orcv1alpha1.ServerResourceSpec) (*orcv1alpha1.ServerGroup, progress.ReconcileStatus) { - if resource.ServerGroupRef == nil { - return &orcv1alpha1.ServerGroup{}, progress.NewReconcileStatus() + if resource.SchedulerHints == nil { + return hints, progress.NewReconcileStatus() } - return getDependencyHelper(ctx, actuator.k8sClient, obj, string(*resource.ServerGroupRef), "ServerGroup", func(sg *orcv1alpha1.ServerGroup) bool { - return orcv1alpha1.IsAvailable(sg) && sg.Status.ID != nil - }, &orcv1alpha1.ServerGroup{}) -} -func (actuator serverActuator) getKeypairHelper(ctx context.Context, obj *orcv1alpha1.Server, resource *orcv1alpha1.ServerResourceSpec) (*orcv1alpha1.KeyPair, progress.ReconcileStatus) { - if resource.KeypairRef == nil { - return &orcv1alpha1.KeyPair{}, progress.NewReconcileStatus() + schedHints := resource.SchedulerHints + reconcileStatus := progress.NewReconcileStatus() + + // Resolve ServerGroupRef to server group ID + sg, sgReconcileStatus := dependency.FetchDependency[*orcv1alpha1.ServerGroup]( + ctx, actuator.k8sClient, obj.Namespace, + schedHints.ServerGroupRef, "ServerGroup", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(sgReconcileStatus) + if sg.Status.ID != nil { + hints.Group = *sg.Status.ID + } + + // Resolve differentHostServerRefs to server IDs + if len(schedHints.DifferentHostServerRefs) > 0 { + differentHost := make([]string, 0, len(schedHints.DifferentHostServerRefs)) + for i := range schedHints.DifferentHostServerRefs { + ref := &schedHints.DifferentHostServerRefs[i] + server, serverReconcileStatus := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, + ref, "Server", + func(s *orcv1alpha1.Server) bool { + return s.Status.ID != nil && + s.Status.Resource != nil && + s.Status.Resource.Status == "ACTIVE" + }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(serverReconcileStatus) + if server.Status.ID != nil { + differentHost = append(differentHost, *server.Status.ID) + } + } + hints.DifferentHost = differentHost + } + + // Resolve sameHostServerRefs to server IDs + if len(schedHints.SameHostServerRefs) > 0 { + sameHost := make([]string, 0, len(schedHints.SameHostServerRefs)) + for i := range schedHints.SameHostServerRefs { + ref := &schedHints.SameHostServerRefs[i] + server, serverReconcileStatus := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, + ref, "Server", + func(s *orcv1alpha1.Server) bool { + return s.Status.ID != nil && + s.Status.Resource != nil && + s.Status.Resource.Status == "ACTIVE" + }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(serverReconcileStatus) + if server.Status.ID != nil { + sameHost = append(sameHost, *server.Status.ID) + } + } + hints.SameHost = sameHost } - return getDependencyHelper(ctx, actuator.k8sClient, obj, string(*resource.KeypairRef), "KeyPair", func(kp *orcv1alpha1.KeyPair) bool { - return orcv1alpha1.IsAvailable(kp) && kp.Status.Resource != nil - }, &orcv1alpha1.KeyPair{}) -} -func (actuator serverActuator) getUserDataHelper(ctx context.Context, obj *orcv1alpha1.Server, resource *orcv1alpha1.ServerResourceSpec) ([]byte, progress.ReconcileStatus) { - if resource.UserData == nil || resource.UserData.SecretRef == nil { - return nil, progress.NewReconcileStatus() + if schedHints.Query != "" { + var query []any + if err := json.Unmarshal([]byte(schedHints.Query), &query); err != nil { + return hints, progress.WrapError(orcerrors.Terminal( + orcv1alpha1.ConditionReasonInvalidConfiguration, + "invalid scheduler hints query: "+err.Error(), err)) + } + hints.Query = query } - secret, reconcileStatus := getDependencyHelper(ctx, actuator.k8sClient, obj, string(*resource.UserData.SecretRef), "Secret", func(s *corev1.Secret) bool { - return true // Secrets don't have availability status - }, &corev1.Secret{}) - if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { - return nil, reconcileStatus + if schedHints.TargetCell != "" { + hints.TargetCell = schedHints.TargetCell } - userData, ok := secret.Data["value"] - if !ok { - return nil, progress.NewReconcileStatus().WithProgressMessage("User data secret does not contain \"value\" key") + hints.DifferentCell = schedHints.DifferentCell + if schedHints.BuildNearHostIP != nil { + hints.BuildNearHostIP = string(ptr.Deref(schedHints.BuildNearHostIP, "")) } - return userData, progress.NewReconcileStatus() + if schedHints.AdditionalProperties != nil { + additionalProps := make(map[string]any, len(schedHints.AdditionalProperties)) + for k, v := range schedHints.AdditionalProperties { + additionalProps[k] = v + } + hints.AdditionalProperties = additionalProps + } + + return hints, reconcileStatus } func (actuator serverActuator) CreateResource(ctx context.Context, obj *orcv1alpha1.Server) (*osResourceT, progress.ReconcileStatus) { @@ -223,26 +253,54 @@ func (actuator serverActuator) CreateResource(ctx context.Context, obj *orcv1alp reconcileStatus := progress.NewReconcileStatus() - var image *orcv1alpha1.Image - { + // Determine if we're booting from volume or image + bootFromVolume := resource.BootVolume != nil + + var imageID string + if !bootFromVolume { + // Traditional boot from image dep, imageReconcileStatus := imageDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(image *orcv1alpha1.Image) bool { - return orcv1alpha1.IsAvailable(image) && image.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(imageReconcileStatus) - image = dep + if dep != nil && dep.Status.ID != nil { + imageID = *dep.Status.ID + } + } + + // Resolve boot volume for boot-from-volume + var blockDevices []servers.BlockDevice + if bootFromVolume { + bootVolume, bvReconcileStatus := bootVolumeDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(bvReconcileStatus) + + if bootVolume != nil && bootVolume.Status.ID != nil { + bd := servers.BlockDevice{ + SourceType: servers.SourceVolume, + DestinationType: servers.DestinationVolume, + UUID: *bootVolume.Status.ID, + BootIndex: 0, // Always 0 for boot volume + } + if resource.BootVolume.Tag != nil { + bd.Tag = *resource.BootVolume.Tag + } + blockDevices = append(blockDevices, bd) + } } - flavor, flavorReconcileStatus := actuator.getFlavorHelper(ctx, obj, resource) + flavor, flavorReconcileStatus := dependency.FetchDependency[*orcv1alpha1.Flavor]( + ctx, actuator.k8sClient, obj.Namespace, + &resource.FlavorRef, "Flavor", + orcv1alpha1.IsAvailable, + ) reconcileStatus = reconcileStatus.WithReconcileStatus(flavorReconcileStatus) portList := make([]servers.Network, len(resource.Ports)) { portsMap, portsReconcileStatus := portDependency.GetDependencies( - ctx, actuator.k8sClient, obj, func(port *orcv1alpha1.Port) bool { - return port.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(portsReconcileStatus) if needsReschedule, _ := portsReconcileStatus.NeedsReschedule(); !needsReschedule { @@ -265,14 +323,33 @@ func (actuator serverActuator) CreateResource(ctx context.Context, obj *orcv1alp } } - serverGroup, serverGroupReconcileStatus := actuator.getServerGroupHelper(ctx, obj, resource) - reconcileStatus = reconcileStatus.WithReconcileStatus(serverGroupReconcileStatus) + schedulerHints, schedulerHintsReconcileStatus := actuator.getSchedulerHints(ctx, obj, resource) + reconcileStatus = reconcileStatus.WithReconcileStatus(schedulerHintsReconcileStatus) - keypair, keypairReconcileStatus := actuator.getKeypairHelper(ctx, obj, resource) + keypair, keypairReconcileStatus := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, + resource.KeypairRef, "KeyPair", + func(kp *orcv1alpha1.KeyPair) bool { return orcv1alpha1.IsAvailable(kp) && kp.Status.Resource != nil }, + ) reconcileStatus = reconcileStatus.WithReconcileStatus(keypairReconcileStatus) - userData, userDataReconcileStatus := actuator.getUserDataHelper(ctx, obj, resource) - reconcileStatus = reconcileStatus.WithReconcileStatus(userDataReconcileStatus) + var userData []byte + if resource.UserData != nil { + secret, secretReconcileStatus := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, + resource.UserData.SecretRef, "Secret", + func(*corev1.Secret) bool { return true }, // Secrets don't have availability status + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(secretReconcileStatus) + if secretReconcileStatus == nil { + var ok bool + userData, ok = secret.Data["value"] + if !ok { + reconcileStatus = reconcileStatus.WithReconcileStatus( + progress.NewReconcileStatus().WithProgressMessage("User data secret does not contain \"value\" key")) + } + } + } if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -285,14 +362,22 @@ func (actuator serverActuator) CreateResource(ctx context.Context, obj *orcv1alp // Sort tags before creation to simplify comparisons slices.Sort(tags) + metadata := make(map[string]string) + for _, m := range resource.Metadata { + metadata[m.Key] = m.Value + } + serverCreateOpts := servers.CreateOpts{ Name: getResourceName(obj), - ImageRef: *image.Status.ID, + ImageRef: imageID, // Empty string if boot-from-volume FlavorRef: *flavor.Status.ID, Networks: portList, UserData: userData, Tags: tags, + Metadata: metadata, AvailabilityZone: resource.AvailabilityZone, + ConfigDrive: resource.ConfigDrive, + BlockDevice: blockDevices, // Boot volume for BFV } /* keypairs.CreateOptsExt was merged into servers.CreateOpts in gopher cloud V3 @@ -306,10 +391,6 @@ func (actuator serverActuator) CreateResource(ctx context.Context, obj *orcv1alp } } - schedulerHints := servers.SchedulerHintOpts{ - Group: ptr.Deref(serverGroup.Status.ID, ""), - } - server, err := actuator.osClient.CreateServer(ctx, createOpts, schedulerHints) // We should require the spec to be updated before retrying a create which returned a non-retryable error @@ -343,6 +424,7 @@ func (actuator serverActuator) GetResourceReconcilers(ctx context.Context, orcOb actuator.checkStatus, actuator.updateResource, actuator.reconcileTags, + actuator.reconcileMetadata, actuator.reconcilePortAttachments, actuator.reconcileVolumeAttachments, }, nil @@ -372,10 +454,10 @@ func (actuator serverActuator) updateResource(ctx context.Context, obj orcObject _, err = actuator.osClient.UpdateServer(ctx, osResource.ID, updateOpts) - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } @@ -429,6 +511,39 @@ func (actuator serverActuator) reconcileTags(ctx context.Context, obj orcObjectP return tags.ReconcileTags[orcObjectPT, osResourceT](obj.Spec.Resource.Tags, ptr.Deref(osResource.Tags, []string{}), tags.NewServerTagReplacer(actuator.osClient, osResource.ID))(ctx, obj, osResource) } +func (actuator serverActuator) reconcileMetadata(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + + // Metadata cannot be set on a server that is still building + if osResource.Status == "" || osResource.Status == ServerStatusBuild { + return progress.NewReconcileStatus().WaitingOnOpenStack(progress.WaitingOnReady, serverActivePollingPeriod) + } + + // Build the desired metadata map from spec + desiredMetadata := make(map[string]string) + for _, m := range resource.Metadata { + desiredMetadata[m.Key] = m.Value + } + + // Compare with current metadata + if maps.Equal(desiredMetadata, osResource.Metadata) { + return nil + } + + log.V(logging.Verbose).Info("Updating server metadata") + _, err := actuator.osClient.ReplaceServerMetadata(ctx, osResource.ID, desiredMetadata) + if err != nil { + return progress.WrapError(err) + } + + return progress.NeedsRefresh() +} + func (actuator serverActuator) reconcilePortAttachments(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { log := ctrl.LoggerFrom(ctx) resource := obj.Spec.Resource @@ -439,9 +554,7 @@ func (actuator serverActuator) reconcilePortAttachments(ctx context.Context, obj } portDepsMap, reconcileStatus := portDependency.GetDependencies( - ctx, actuator.k8sClient, obj, func(port *orcv1alpha1.Port) bool { - return port.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { @@ -519,9 +632,7 @@ func (actuator serverActuator) reconcileVolumeAttachments(ctx context.Context, o } volumeDepsMap, reconcileStatus := volumeDependency.GetDependencies( - ctx, actuator.k8sClient, obj, func(volume *orcv1alpha1.Volume) bool { - return orcv1alpha1.IsAvailable(volume) && volume.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { diff --git a/internal/controllers/server/controller.go b/internal/controllers/server/controller.go index 95ac9f595..71f7ce311 100644 --- a/internal/controllers/server/controller.go +++ b/internal/controllers/server/controller.go @@ -19,6 +19,7 @@ package server import ( "context" "errors" + "time" corev1 "k8s.io/api/core/v1" ctrl "sigs.k8s.io/controller-runtime" @@ -38,17 +39,22 @@ import ( // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=servers/status,verbs=get;update;patch type serverReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return serverReconcilerConstructor{scopeFactory: scopeFactory} + return &serverReconcilerConstructor{scopeFactory: scopeFactory} } func (serverReconcilerConstructor) GetName() string { return controllerName } +func (c *serverReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + const controllerName = "server" var ( @@ -73,13 +79,31 @@ var ( "spec.resource.imageRef", func(server *orcv1alpha1.Server) []string { resource := server.Spec.Resource - if resource == nil { + if resource == nil || resource.ImageRef == nil { return nil } - return []string{string(resource.ImageRef)} + return []string{string(*resource.ImageRef)} + }, + finalizer, externalObjectFieldOwner, + ) + + // bootVolumeDependency handles the boot volume specified in bootVolume for boot-from-volume. + // This volume is attached at server creation time as the root disk. + // deletion guard is in place because the server cannot boot without its root volume. + // OverrideDependencyName is used to avoid conflict with volumeDependency which also + // creates a Volume deletion guard for Server. + bootVolumeDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ServerList, *orcv1alpha1.Volume]( + "spec.resource.bootVolume.volumeRef", + func(server *orcv1alpha1.Server) []string { + resource := server.Spec.Resource + if resource == nil || resource.BootVolume == nil { + return nil + } + return []string{string(resource.BootVolume.VolumeRef)} }, finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("bootvolume"), ) portDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ServerList, *orcv1alpha1.Port]( @@ -105,14 +129,14 @@ var ( // No deletion guard for server group, because server group can be safely deleted while // referenced by a server serverGroupDependency = dependency.NewDependency[*orcv1alpha1.ServerList, *orcv1alpha1.ServerGroup]( - "spec.resource.serverGroupRef", + "spec.resource.schedulerHints.serverGroupRef", func(server *orcv1alpha1.Server) []string { resource := server.Spec.Resource - if resource == nil || resource.ServerGroupRef == nil { + if resource == nil || resource.SchedulerHints == nil || resource.SchedulerHints.ServerGroupRef == nil { return nil } - return []string{string(*resource.ServerGroupRef)} + return []string{string(*resource.SchedulerHints.ServerGroupRef)} }, ) @@ -161,10 +185,44 @@ var ( }, finalizer, externalObjectFieldOwner, ) + + // No deletion guard for server references in scheduler hints, because they + // are only used on creation for placement decisions + sameHostServerRefDependency = dependency.NewDependency[*orcv1alpha1.ServerList, *orcv1alpha1.Server]( + "spec.resource.schedulerHints.sameHostServerRefs", + func(server *orcv1alpha1.Server) []string { + resource := server.Spec.Resource + if resource == nil || resource.SchedulerHints == nil { + return nil + } + + refs := make([]string, 0, len(resource.SchedulerHints.SameHostServerRefs)) + for _, ref := range resource.SchedulerHints.SameHostServerRefs { + refs = append(refs, string(ref)) + } + return refs + }, + ) + + differentHostServerRefDependency = dependency.NewDependency[*orcv1alpha1.ServerList, *orcv1alpha1.Server]( + "spec.resource.schedulerHints.differentHostServerRefs", + func(server *orcv1alpha1.Server) []string { + resource := server.Spec.Resource + if resource == nil || resource.SchedulerHints == nil { + return nil + } + + refs := make([]string, 0, len(resource.SchedulerHints.DifferentHostServerRefs)) + for _, ref := range resource.SchedulerHints.DifferentHostServerRefs { + refs = append(refs, string(ref)) + } + return refs + }, + ) ) // SetupWithManager sets up the controller with the Manager. -func (c serverReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *serverReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := mgr.GetLogger().WithValues("controller", controllerName) k8sClient := mgr.GetClient() @@ -196,6 +254,18 @@ func (c serverReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c if err != nil { return err } + bootVolumeWatchEventHandler, err := bootVolumeDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + sameHostServerRefWatchEventHandler, err := sameHostServerRefDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + differentHostServerRefWatchEventHandler, err := differentHostServerRefDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } builder := ctrl.NewControllerManagedBy(mgr). WithOptions(options). @@ -215,9 +285,18 @@ func (c serverReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c Watches(&orcv1alpha1.Volume{}, volumeWatchEventHandler, builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Volume{})), ). + Watches(&orcv1alpha1.Volume{}, bootVolumeWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Volume{})), + ). Watches(&orcv1alpha1.KeyPair{}, keypairWatchEventHandler, builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.KeyPair{})), ). + Watches(&orcv1alpha1.Server{}, sameHostServerRefWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Server{})), + ). + Watches(&orcv1alpha1.Server{}, differentHostServerRefWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Server{})), + ). // XXX: This is a general watch on secrets. A general watch on secrets // is undesirable because: // - It requires problematic RBAC @@ -234,13 +313,16 @@ func (c serverReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c serverGroupDependency.AddToManager(ctx, mgr), userDataDependency.AddToManager(ctx, mgr), volumeDependency.AddToManager(ctx, mgr), + bootVolumeDependency.AddToManager(ctx, mgr), keypairDependency.AddToManager(ctx, mgr), + sameHostServerRefDependency.AddToManager(ctx, mgr), + differentHostServerRefDependency.AddToManager(ctx, mgr), credentialsDependency.AddToManager(ctx, mgr), credentials.AddCredentialsWatch(log, k8sClient, builder, credentialsDependency), ); err != nil { return err } - r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, serverHelperFactory{}, serverStatusWriter{}) + r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, serverHelperFactory{}, serverStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/server/status.go b/internal/controllers/server/status.go index aa7c47ccf..39956c531 100644 --- a/internal/controllers/server/status.go +++ b/internal/controllers/server/status.go @@ -18,6 +18,8 @@ package server import ( "fmt" + "maps" + "slices" "github.com/go-logr/logr" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -69,7 +71,8 @@ func (serverStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osRes WithHostID(osResource.HostID). WithAvailabilityZone(osResource.AvailabilityZone). WithServerGroups(ptr.Deref(osResource.ServerGroups, []string{})...). - WithTags(ptr.Deref(osResource.Tags, []string{})...) + WithTags(ptr.Deref(osResource.Tags, []string{})...). + WithConfigDrive(osResource.ConfigDrive) if imageID, ok := osResource.Image["id"]; ok { status.WithImageID(fmt.Sprintf("%s", imageID)) @@ -97,5 +100,12 @@ func (serverStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osRes status.WithInterfaces(interfaceStatus) } + // Sort metadata keys for deterministic output + for _, k := range slices.Sorted(maps.Keys(osResource.Metadata)) { + status.WithMetadata(orcapplyconfigv1alpha1.ServerMetadataStatus(). + WithKey(k). + WithValue(osResource.Metadata[k])) + } + statusApply.WithResource(status) } diff --git a/internal/controllers/server/tests/server-boot-from-volume/00-assert.yaml b/internal/controllers/server/tests/server-boot-from-volume/00-assert.yaml new file mode 100644 index 000000000..4fa211ad6 --- /dev/null +++ b/internal/controllers/server/tests/server-boot-from-volume/00-assert.yaml @@ -0,0 +1,61 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Server + name: server-boot-from-volume + ref: server + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Volume + name: server-boot-from-volume + ref: volume + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: server-boot-from-volume + ref: port + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: server-boot-from-volume + ref: network + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Subnet + name: server-boot-from-volume + ref: subnet +assertAll: + - celExpr: "server.status.resource.hostID != ''" + - celExpr: "server.status.resource.availabilityZone != ''" + # Verify the server booted from volume (imageID may be empty for BFV servers) + - celExpr: "port.status.resource.deviceID == server.status.id" + - celExpr: "port.status.resource.status == 'ACTIVE'" + - celExpr: "size(server.status.resource.interfaces) == 1" + - celExpr: "server.status.resource.interfaces[0].portID == port.status.id" + - celExpr: "server.status.resource.interfaces[0].netID == network.status.id" + - celExpr: "server.status.resource.interfaces[0].macAddr != ''" + - celExpr: "server.status.resource.interfaces[0].portState != ''" + - celExpr: "size(server.status.resource.interfaces[0].fixedIPs) >= 1" + - celExpr: "server.status.resource.interfaces[0].fixedIPs[0].ipAddress != ''" + - celExpr: "server.status.resource.interfaces[0].fixedIPs[0].subnetID == subnet.status.id" + # Verify volume is bootable + - celExpr: "volume.status.resource.bootable == true" + # Verify volume is attached to the server + - celExpr: "size(volume.status.resource.attachments) == 1" + - celExpr: "volume.status.resource.attachments[0].serverID == server.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Server +metadata: + name: server-boot-from-volume +status: + resource: + name: server-boot-from-volume + status: ACTIVE +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Volume +metadata: + name: server-boot-from-volume +status: + resource: + bootable: true + status: in-use diff --git a/internal/controllers/server/tests/server-boot-from-volume/00-create-resource.yaml b/internal/controllers/server/tests/server-boot-from-volume/00-create-resource.yaml new file mode 100644 index 000000000..e14a11c45 --- /dev/null +++ b/internal/controllers/server/tests/server-boot-from-volume/00-create-resource.yaml @@ -0,0 +1,30 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: server-boot-from-volume +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: server-boot-from-volume + addresses: + - subnetRef: server-boot-from-volume +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Server +metadata: + name: server-boot-from-volume +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + # Note: No imageRef - booting from volume! + bootVolume: + volumeRef: server-boot-from-volume + flavorRef: server-boot-from-volume + ports: + - portRef: server-boot-from-volume diff --git a/internal/controllers/server/tests/server-boot-from-volume/00-prerequisites.yaml b/internal/controllers/server/tests/server-boot-from-volume/00-prerequisites.yaml new file mode 100644 index 000000000..a75dc4d64 --- /dev/null +++ b/internal/controllers/server/tests/server-boot-from-volume/00-prerequisites.yaml @@ -0,0 +1,63 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true + - script: | + export E2E_KUTTL_CURRENT_TEST=server-boot-from-volume + cat ../templates/create-flavor.tmpl | envsubst | kubectl -n ${NAMESPACE} apply -f - +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Image +metadata: + name: server-boot-from-volume +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + content: + diskFormat: qcow2 + download: + url: https://github.com/k-orc/openstack-resource-controller/raw/2ddc1857f5e22d2f0df6f5ee033353e4fd907121/internal/controllers/image/testdata/cirros-0.6.3-x86_64-disk.img + visibility: public +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: server-boot-from-volume +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: server-boot-from-volume +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: server-boot-from-volume +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: server-boot-from-volume + ipVersion: 4 + cidr: 192.168.201.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Volume +metadata: + name: server-boot-from-volume +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + size: 1 + imageRef: server-boot-from-volume diff --git a/internal/controllers/server/tests/server-boot-from-volume/README.md b/internal/controllers/server/tests/server-boot-from-volume/README.md new file mode 100644 index 000000000..0a26653ad --- /dev/null +++ b/internal/controllers/server/tests/server-boot-from-volume/README.md @@ -0,0 +1,14 @@ +# Boot from Volume Test + +This test creates a server that boots from a Cinder volume instead of an +image. This is the boot-from-volume (BFV) pattern where: + +1. An image is created +2. A bootable volume is created from that image +3. A server is created booting from the volume (no imageRef) + +The test verifies: +- Server reaches ACTIVE state +- Volume is marked as bootable +- Volume is attached to the server +- Port is attached to the server diff --git a/internal/controllers/server/tests/server-create-full/00-assert.yaml b/internal/controllers/server/tests/server-create-full/00-assert.yaml index 5f351d6d1..14b3d5be7 100644 --- a/internal/controllers/server/tests/server-create-full/00-assert.yaml +++ b/internal/controllers/server/tests/server-create-full/00-assert.yaml @@ -14,6 +14,14 @@ resourceRefs: kind: Port name: server-create-full ref: port + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: server-create-full-dummy + ref: portDummy + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Server + name: server-create-full-dummy + ref: serverDummy - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: ServerGroup name: server-create-full @@ -35,7 +43,9 @@ resourceRefs: name: server-create-full ref: subnet assertAll: + - celExpr: "serverDummy.status.resource.status == 'ACTIVE'" - celExpr: "server.status.resource.hostID != ''" + - celExpr: "server.status.resource.hostID == serverDummy.status.resource.hostID" - celExpr: "server.status.resource.availabilityZone == 'nova'" - celExpr: "server.status.resource.imageID == image.status.id" - celExpr: "server.status.resource.serverGroups[0] == sg.status.id" @@ -66,3 +76,9 @@ status: tags: - tag1 - tag2 + metadata: + - key: environment + value: test + - key: owner + value: kuttl + configDrive: true diff --git a/internal/controllers/server/tests/server-create-full/00-create-resource.yaml b/internal/controllers/server/tests/server-create-full/00-create-resource.yaml index 006b18145..a06c5e43d 100644 --- a/internal/controllers/server/tests/server-create-full/00-create-resource.yaml +++ b/internal/controllers/server/tests/server-create-full/00-create-resource.yaml @@ -14,6 +14,20 @@ spec: - subnetRef: server-create-full --- apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: server-create-full-dummy +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: server-create-full + addresses: + - subnetRef: server-create-full +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Volume metadata: name: server-create-full @@ -27,6 +41,21 @@ spec: --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Server +metadata: + name: server-create-full-dummy +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + imageRef: server-create-full + flavorRef: server-create-full + ports: + - portRef: server-create-full-dummy +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Server metadata: name: server-create-full spec: @@ -40,11 +69,24 @@ spec: flavorRef: server-create-full ports: - portRef: server-create-full - serverGroupRef: server-create-full keypairRef: server-create-full + schedulerHints: + serverGroupRef: server-create-full + query: '[">=", "$free_ram_mb", 32]' + buildNearHostIP: 10.0.0.0/8 + additionalProperties: + custom_hint: custom_value + sameHostServerRefs: + - server-create-full-dummy volumes: - volumeRef: server-create-full availabilityZone: nova tags: - tag1 - tag2 + metadata: + - key: environment + value: test + - key: owner + value: kuttl + configDrive: true diff --git a/internal/controllers/server/tests/server-dependency/00-create-everything-but-flavor.yaml b/internal/controllers/server/tests/server-dependency/00-create-everything-but-flavor.yaml index 101976fcf..ae93fc454 100644 --- a/internal/controllers/server/tests/server-dependency/00-create-everything-but-flavor.yaml +++ b/internal/controllers/server/tests/server-dependency/00-create-everything-but-flavor.yaml @@ -87,6 +87,7 @@ spec: flavorRef: server-dependency ports: - portRef: server-dependency - serverGroupRef: server-dependency + schedulerHints: + serverGroupRef: server-dependency userData: secretRef: server-dependency \ No newline at end of file diff --git a/internal/controllers/server/tests/server-dependency/01-create-everything-but-image.yaml b/internal/controllers/server/tests/server-dependency/01-create-everything-but-image.yaml index 5757e4eea..a669f622f 100644 --- a/internal/controllers/server/tests/server-dependency/01-create-everything-but-image.yaml +++ b/internal/controllers/server/tests/server-dependency/01-create-everything-but-image.yaml @@ -27,6 +27,7 @@ spec: flavorRef: server-dependency ports: - portRef: server-dependency - serverGroupRef: server-dependency + schedulerHints: + serverGroupRef: server-dependency userData: secretRef: server-dependency diff --git a/internal/controllers/server/tests/server-dependency/02-create-everything-but-port.yaml b/internal/controllers/server/tests/server-dependency/02-create-everything-but-port.yaml index 4dd1e19b0..45f5348cc 100644 --- a/internal/controllers/server/tests/server-dependency/02-create-everything-but-port.yaml +++ b/internal/controllers/server/tests/server-dependency/02-create-everything-but-port.yaml @@ -38,6 +38,7 @@ spec: flavorRef: server-dependency ports: - portRef: server-dependency - serverGroupRef: server-dependency + schedulerHints: + serverGroupRef: server-dependency userData: secretRef: server-dependency diff --git a/internal/controllers/server/tests/server-dependency/03-create-everything-but-server-group.yaml b/internal/controllers/server/tests/server-dependency/03-create-everything-but-server-group.yaml index 6483cf47f..f15e8960e 100644 --- a/internal/controllers/server/tests/server-dependency/03-create-everything-but-server-group.yaml +++ b/internal/controllers/server/tests/server-dependency/03-create-everything-but-server-group.yaml @@ -37,6 +37,7 @@ spec: flavorRef: server-dependency ports: - portRef: server-dependency - serverGroupRef: server-dependency + schedulerHints: + serverGroupRef: server-dependency userData: secretRef: server-dependency diff --git a/internal/controllers/server/tests/server-dependency/04-create-everything-but-userdata-secret.yaml b/internal/controllers/server/tests/server-dependency/04-create-everything-but-userdata-secret.yaml index bc9196a80..f8b8b4d02 100644 --- a/internal/controllers/server/tests/server-dependency/04-create-everything-but-userdata-secret.yaml +++ b/internal/controllers/server/tests/server-dependency/04-create-everything-but-userdata-secret.yaml @@ -35,6 +35,7 @@ spec: flavorRef: server-dependency ports: - portRef: server-dependency - serverGroupRef: server-dependency + schedulerHints: + serverGroupRef: server-dependency userData: secretRef: server-dependency diff --git a/internal/controllers/server/tests/server-dependency/05-create-everything-but-keypair.yaml b/internal/controllers/server/tests/server-dependency/05-create-everything-but-keypair.yaml index eb4776259..031ed37ac 100644 --- a/internal/controllers/server/tests/server-dependency/05-create-everything-but-keypair.yaml +++ b/internal/controllers/server/tests/server-dependency/05-create-everything-but-keypair.yaml @@ -27,7 +27,8 @@ spec: flavorRef: server-dependency ports: - portRef: server-dependency - serverGroupRef: server-dependency + schedulerHints: + serverGroupRef: server-dependency keypairRef: server-dependency userData: secretRef: server-dependency diff --git a/internal/controllers/server/tests/server-update/00-assert.yaml b/internal/controllers/server/tests/server-update/00-assert.yaml index 551244650..6964361e5 100644 --- a/internal/controllers/server/tests/server-update/00-assert.yaml +++ b/internal/controllers/server/tests/server-update/00-assert.yaml @@ -24,6 +24,7 @@ assertAll: - celExpr: "server.status.resource.serverGroups[0] == sg.status.id" - celExpr: "!has(server.status.resource.tags)" - celExpr: "!has(server.status.resource.volumes)" + - celExpr: "!has(server.status.resource.metadata)" - celExpr: "size(server.status.resource.interfaces) == 1" - celExpr: "server.status.resource.interfaces[0].portID == port.status.id" --- diff --git a/internal/controllers/server/tests/server-update/00-minimal-resource.yaml b/internal/controllers/server/tests/server-update/00-minimal-resource.yaml index 4a62a151a..95dca9e29 100644 --- a/internal/controllers/server/tests/server-update/00-minimal-resource.yaml +++ b/internal/controllers/server/tests/server-update/00-minimal-resource.yaml @@ -13,4 +13,5 @@ spec: flavorRef: server-update ports: - portRef: server-update - serverGroupRef: server-update \ No newline at end of file + schedulerHints: + serverGroupRef: server-update \ No newline at end of file diff --git a/internal/controllers/server/tests/server-update/01-assert.yaml b/internal/controllers/server/tests/server-update/01-assert.yaml index 473aecab0..db83497d8 100644 --- a/internal/controllers/server/tests/server-update/01-assert.yaml +++ b/internal/controllers/server/tests/server-update/01-assert.yaml @@ -54,6 +54,11 @@ status: tags: - tag1 - tag2 + metadata: + - key: environment + value: staging + - key: team + value: platform conditions: - type: Available status: "True" diff --git a/internal/controllers/server/tests/server-update/01-updated-resource.yaml b/internal/controllers/server/tests/server-update/01-updated-resource.yaml index 248b328a2..ae0cac6df 100644 --- a/internal/controllers/server/tests/server-update/01-updated-resource.yaml +++ b/internal/controllers/server/tests/server-update/01-updated-resource.yaml @@ -44,3 +44,8 @@ spec: tags: - tag1 - tag2 + metadata: + - key: environment + value: staging + - key: team + value: platform diff --git a/internal/controllers/server/tests/server-update/02-assert.yaml b/internal/controllers/server/tests/server-update/02-assert.yaml index 68beeb722..ec2db2777 100644 --- a/internal/controllers/server/tests/server-update/02-assert.yaml +++ b/internal/controllers/server/tests/server-update/02-assert.yaml @@ -32,6 +32,7 @@ assertAll: - celExpr: "server.status.resource.serverGroups[0] == sg.status.id" - celExpr: "!has(server.status.resource.tags)" - celExpr: "!has(server.status.resource.volumes)" + - celExpr: "!has(server.status.resource.metadata)" - celExpr: "!has(volume.status.resource.attachments)" - celExpr: "port1.status.resource.deviceID == server.status.id" - celExpr: "port1.status.resource.status == 'ACTIVE'" diff --git a/internal/controllers/server/zz_generated.adapter.go b/internal/controllers/server/zz_generated.adapter.go index 340fff439..a18d78c8e 100644 --- a/internal/controllers/server/zz_generated.adapter.go +++ b/internal/controllers/server/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package server import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/server/zz_generated.controller.go b/internal/controllers/server/zz_generated.controller.go index 6a5156eb0..d3aee5648 100644 --- a/internal/controllers/server/zz_generated.controller.go +++ b/internal/controllers/server/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/servergroup/actuator.go b/internal/controllers/servergroup/actuator.go index 78ab5499f..04dd07975 100644 --- a/internal/controllers/servergroup/actuator.go +++ b/internal/controllers/servergroup/actuator.go @@ -22,6 +22,7 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servergroups" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" @@ -72,15 +73,13 @@ func (actuator servergroupActuator) ListOSResourcesForAdoption(ctx context.Conte return nil, false } - var filters []osclients.ResourceFilter[osResourceT] - listOpts := servergroups.ListOpts{} - - filters = append(filters, + filters := []osclients.ResourceFilter[osResourceT]{ func(f *servergroups.ServerGroup) bool { name := getResourceName(orcObject) - return f.Name == name + return f.Name == name && ptr.Deref(f.Policy, "") == string(resourceSpec.Policy) }, - ) + } + listOpts := servergroups.ListOpts{} return actuator.listOSResources(ctx, filters, &listOpts), true } diff --git a/internal/controllers/servergroup/controller.go b/internal/controllers/servergroup/controller.go index 98069dc81..fa63d245d 100644 --- a/internal/controllers/servergroup/controller.go +++ b/internal/controllers/servergroup/controller.go @@ -19,6 +19,7 @@ package servergroup import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -37,19 +38,24 @@ const controllerName = "servergroup" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=servergroups/status,verbs=get;update;patch type servergroupReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return servergroupReconcilerConstructor{scopeFactory: scopeFactory} + return &servergroupReconcilerConstructor{scopeFactory: scopeFactory} } func (servergroupReconcilerConstructor) GetName() string { return controllerName } +func (c *servergroupReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c servergroupReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *servergroupReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) builder := ctrl.NewControllerManagedBy(mgr). @@ -63,6 +69,6 @@ func (c servergroupReconcilerConstructor) SetupWithManager(ctx context.Context, return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, servergroupHelperFactory{}, servergroupStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, servergroupHelperFactory{}, servergroupStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/servergroup/zz_generated.adapter.go b/internal/controllers/servergroup/zz_generated.adapter.go index ee366d633..2fc71f170 100644 --- a/internal/controllers/servergroup/zz_generated.adapter.go +++ b/internal/controllers/servergroup/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package servergroup import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/servergroup/zz_generated.controller.go b/internal/controllers/servergroup/zz_generated.controller.go index 8da2d169d..181f872cc 100644 --- a/internal/controllers/servergroup/zz_generated.controller.go +++ b/internal/controllers/servergroup/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/service/actuator.go b/internal/controllers/service/actuator.go index 75e5be2e0..70688ae9d 100644 --- a/internal/controllers/service/actuator.go +++ b/internal/controllers/service/actuator.go @@ -156,12 +156,10 @@ func (actuator serviceActuator) updateResource(ctx context.Context, obj orcObjec _, err = actuator.osClient.UpdateService(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/service/controller.go b/internal/controllers/service/controller.go index 6e46a0dbd..195d4988d 100644 --- a/internal/controllers/service/controller.go +++ b/internal/controllers/service/controller.go @@ -19,6 +19,7 @@ package service import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -37,19 +38,24 @@ const controllerName = "service" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=services/status,verbs=get;update;patch type serviceReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return serviceReconcilerConstructor{scopeFactory: scopeFactory} + return &serviceReconcilerConstructor{scopeFactory: scopeFactory} } func (serviceReconcilerConstructor) GetName() string { return controllerName } +func (c *serviceReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c serviceReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *serviceReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) builder := ctrl.NewControllerManagedBy(mgr). @@ -63,6 +69,6 @@ func (c serviceReconcilerConstructor) SetupWithManager(ctx context.Context, mgr return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, serviceHelperFactory{}, serviceStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, serviceHelperFactory{}, serviceStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/service/zz_generated.adapter.go b/internal/controllers/service/zz_generated.adapter.go index 3f8d585bc..719f23b25 100644 --- a/internal/controllers/service/zz_generated.adapter.go +++ b/internal/controllers/service/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package service import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/service/zz_generated.controller.go b/internal/controllers/service/zz_generated.controller.go index a1fe4a121..0e0232fae 100644 --- a/internal/controllers/service/zz_generated.controller.go +++ b/internal/controllers/service/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/sharenetwork/actuator.go b/internal/controllers/sharenetwork/actuator.go new file mode 100644 index 000000000..fe08ea788 --- /dev/null +++ b/internal/controllers/sharenetwork/actuator.go @@ -0,0 +1,253 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sharenetwork + +import ( + "context" + "iter" + + "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharenetworks" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// OpenStack resource types +type ( + osResourceT = sharenetworks.ShareNetwork + + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + resourceReconciler = interfaces.ResourceReconciler[orcObjectPT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) + +type sharenetworkActuator struct { + osClient osclients.ShareNetworkClient + k8sClient client.Client +} + +var _ createResourceActuator = sharenetworkActuator{} +var _ deleteResourceActuator = sharenetworkActuator{} + +func (sharenetworkActuator) GetResourceID(osResource *osResourceT) string { + return osResource.ID +} + +func (actuator sharenetworkActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) { + resource, err := actuator.osClient.GetShareNetwork(ctx, id) + if err != nil { + return nil, progress.WrapError(err) + } + return resource, nil +} + +func (actuator sharenetworkActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + listOpts := sharenetworks.ListOpts{ + Name: getResourceName(orcObject), + } + + return actuator.osClient.ListShareNetworks(ctx, listOpts), true +} + +func (actuator sharenetworkActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + listOpts := sharenetworks.ListOpts{ + Name: string(ptr.Deref(filter.Name, "")), + Description: ptr.Deref(filter.Description, ""), + } + + return actuator.osClient.ListShareNetworks(ctx, listOpts), nil +} + +func (actuator sharenetworkActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + var reconcileStatus progress.ReconcileStatus + + var networkID string + if resource.NetworkRef != nil { + network, networkDepRS := networkDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(networkDepRS) + if network != nil { + networkID = ptr.Deref(network.Status.ID, "") + } + } + + var subnetID string + if resource.SubnetRef != nil { + subnet, subnetDepRS := subnetDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(subnetDepRS) + if subnet != nil { + subnetID = ptr.Deref(subnet.Status.ID, "") + } + } + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + createOpts := sharenetworks.CreateOpts{ + Name: getResourceName(obj), + Description: ptr.Deref(resource.Description, ""), + NeutronNetID: networkID, + NeutronSubnetID: subnetID, + } + + osResource, err := actuator.osClient.CreateShareNetwork(ctx, createOpts) + if err != nil { + // We should require the spec to be updated before retrying a create which returned a conflict + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + return osResource, nil +} + +func (actuator sharenetworkActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + return progress.WrapError(actuator.osClient.DeleteShareNetwork(ctx, resource.ID)) +} + +func (actuator sharenetworkActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + // Should have been caught by API validation + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + + updateOpts := sharenetworks.UpdateOpts{} + + handleNameUpdate(&updateOpts, obj, osResource) + handleDescriptionUpdate(&updateOpts, resource, osResource) + + needsUpdate, err := needsUpdate(updateOpts) + if err != nil { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err)) + } + if !needsUpdate { + log.V(logging.Debug).Info("No changes") + return nil + } + + _, err = actuator.osClient.UpdateShareNetwork(ctx, osResource.ID, updateOpts) + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) + } + + return progress.NeedsRefresh() +} + +func needsUpdate(updateOpts sharenetworks.UpdateOptsBuilder) (bool, error) { + updateOptsMap, err := updateOpts.ToShareNetworkUpdateMap() + if err != nil { + return false, err + } + + updateMap, ok := updateOptsMap["share_network"].(map[string]any) + if !ok { + updateMap = make(map[string]any) + } + + return len(updateMap) > 0, nil +} + +func handleNameUpdate(updateOpts *sharenetworks.UpdateOpts, obj orcObjectPT, osResource *osResourceT) { + name := getResourceName(obj) + if osResource.Name != name { + updateOpts.Name = &name + } +} + +func handleDescriptionUpdate(updateOpts *sharenetworks.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + description := ptr.Deref(resource.Description, "") + if osResource.Description != description { + updateOpts.Description = &description + } +} + +func (actuator sharenetworkActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.updateResource, + }, nil +} + +type sharenetworkHelperFactory struct{} + +var _ helperFactory = sharenetworkHelperFactory{} + +func newActuator(ctx context.Context, orcObject *orcv1alpha1.ShareNetwork, controller interfaces.ResourceController) (sharenetworkActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, controller.GetK8sClient(), orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return sharenetworkActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject) + if err != nil { + return sharenetworkActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewShareNetworkClient() + if err != nil { + return sharenetworkActuator{}, progress.WrapError(err) + } + + return sharenetworkActuator{ + osClient: osClient, + k8sClient: controller.GetK8sClient(), + }, nil +} + +func (sharenetworkHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { + return sharenetworkAdapter{obj} +} + +func (sharenetworkHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} + +func (sharenetworkHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} diff --git a/internal/controllers/sharenetwork/actuator_test.go b/internal/controllers/sharenetwork/actuator_test.go new file mode 100644 index 000000000..ce963f186 --- /dev/null +++ b/internal/controllers/sharenetwork/actuator_test.go @@ -0,0 +1,119 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sharenetwork + +import ( + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharenetworks" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "k8s.io/utils/ptr" +) + +func TestNeedsUpdate(t *testing.T) { + testCases := []struct { + name string + updateOpts sharenetworks.UpdateOpts + expectChange bool + }{ + { + name: "Empty base opts", + updateOpts: sharenetworks.UpdateOpts{}, + expectChange: false, + }, + { + name: "Updated opts", + updateOpts: sharenetworks.UpdateOpts{Name: ptr.To("updated")}, + expectChange: true, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + got, _ := needsUpdate(tt.updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestHandleNameUpdate(t *testing.T) { + ptrToName := ptr.To[orcv1alpha1.OpenStackName] + testCases := []struct { + name string + newValue *orcv1alpha1.OpenStackName + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToName("name"), existingValue: "name", expectChange: false}, + {name: "Different", newValue: ptrToName("new-name"), existingValue: "name", expectChange: true}, + {name: "No value provided, existing is identical to object name", newValue: nil, existingValue: "object-name", expectChange: false}, + {name: "No value provided, existing is different from object name", newValue: nil, existingValue: "different-from-object-name", expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.ShareNetwork{} + resource.Name = "object-name" + resource.Spec = orcv1alpha1.ShareNetworkSpec{ + Resource: &orcv1alpha1.ShareNetworkResourceSpec{Name: tt.newValue}, + } + osResource := &osResourceT{Name: tt.existingValue} + + updateOpts := sharenetworks.UpdateOpts{} + handleNameUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleDescriptionUpdate(t *testing.T) { + ptrToDescription := ptr.To[string] + testCases := []struct { + name string + newValue *string + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToDescription("desc"), existingValue: "desc", expectChange: false}, + {name: "Different", newValue: ptrToDescription("new-desc"), existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is set", newValue: nil, existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is empty", newValue: nil, existingValue: "", expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.ShareNetworkResourceSpec{Description: tt.newValue} + osResource := &osResourceT{Description: tt.existingValue} + + updateOpts := sharenetworks.UpdateOpts{} + handleDescriptionUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} diff --git a/internal/controllers/sharenetwork/controller.go b/internal/controllers/sharenetwork/controller.go new file mode 100644 index 000000000..a1a970330 --- /dev/null +++ b/internal/controllers/sharenetwork/controller.go @@ -0,0 +1,120 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sharenetwork + +import ( + "context" + "errors" + "time" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "sharenetwork" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=sharenetworks,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=sharenetworks/status,verbs=get;update;patch + +type sharenetworkReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return &sharenetworkReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (sharenetworkReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *sharenetworkReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var networkDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ShareNetworkList, *orcv1alpha1.Network]( + "spec.resource.networkRef", + func(sharenetwork *orcv1alpha1.ShareNetwork) []string { + resource := sharenetwork.Spec.Resource + if resource == nil || resource.NetworkRef == nil { + return nil + } + return []string{string(*resource.NetworkRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var subnetDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.ShareNetworkList, *orcv1alpha1.Subnet]( + "spec.resource.subnetRef", + func(sharenetwork *orcv1alpha1.ShareNetwork) []string { + resource := sharenetwork.Spec.Resource + if resource == nil || resource.SubnetRef == nil { + return nil + } + return []string{string(*resource.SubnetRef)} + }, + finalizer, externalObjectFieldOwner, +) + +// SetupWithManager sets up the controller with the Manager. +func (c *sharenetworkReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + networkWatchEventHandler, err := networkDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + subnetWatchEventHandler, err := subnetDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + Watches(&orcv1alpha1.Network{}, networkWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Network{})), + ). + Watches(&orcv1alpha1.Subnet{}, subnetWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Subnet{})), + ). + For(&orcv1alpha1.ShareNetwork{}) + + if err := errors.Join( + networkDependency.AddToManager(ctx, mgr), + subnetDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, sharenetworkHelperFactory{}, sharenetworkStatusWriter{}, c.defaultResyncPeriod) + return builder.Complete(&r) +} diff --git a/internal/controllers/sharenetwork/status.go b/internal/controllers/sharenetwork/status.go new file mode 100644 index 000000000..fe9da2501 --- /dev/null +++ b/internal/controllers/sharenetwork/status.go @@ -0,0 +1,100 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sharenetwork + +import ( + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type sharenetworkStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.ShareNetworkApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.ShareNetworkStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.ShareNetwork, *osResourceT, *objectApplyT, *statusApplyT] = sharenetworkStatusWriter{} + +func (sharenetworkStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.ShareNetwork(name, namespace) +} + +func (sharenetworkStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.ShareNetwork, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource == nil { + if orcObject.Status.ID == nil { + return metav1.ConditionFalse, nil + } + return metav1.ConditionUnknown, nil + } + + // Share networks become available immediately after creation + // No async operations to wait for + return metav1.ConditionTrue, nil +} + +func (sharenetworkStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.ShareNetworkResourceStatus() + + if osResource.Name != "" { + resourceStatus.WithName(osResource.Name) + } + + if osResource.NeutronNetID != "" { + resourceStatus.WithNeutronNetID(osResource.NeutronNetID) + } + + if osResource.NeutronSubnetID != "" { + resourceStatus.WithNeutronSubnetID(osResource.NeutronSubnetID) + } + + if osResource.NetworkType != "" { + resourceStatus.WithNetworkType(osResource.NetworkType) + } + + // Always set CIDR field, even if empty, so it's always present in status + resourceStatus.WithCIDR(osResource.CIDR) + + if osResource.ProjectID != "" { + resourceStatus.WithProjectID(osResource.ProjectID) + } + + if osResource.Description != "" { + resourceStatus.WithDescription(osResource.Description) + } + + if osResource.SegmentationID != 0 { + resourceStatus.WithSegmentationID(int32(osResource.SegmentationID)) + } + + if osResource.IPVersion != 0 { + resourceStatus.WithIPVersion(int32(osResource.IPVersion)) + } + + if !osResource.CreatedAt.IsZero() { + resourceStatus.WithCreatedAt(metav1.Time{Time: osResource.CreatedAt}) + } + + if !osResource.UpdatedAt.IsZero() { + resourceStatus.WithUpdatedAt(metav1.Time{Time: osResource.UpdatedAt}) + } + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-assert.yaml new file mode 100644 index 000000000..6b5e4a0ab --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-assert.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-create-full +status: + resource: + name: sharenetwork-create-full-override + description: ShareNetwork from "create full" test + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-create-full + ref: sharenetwork + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: sharenetwork-create-full + ref: network + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Subnet + name: sharenetwork-create-full + ref: subnet +assertAll: + - celExpr: "sharenetwork.status.id != ''" + - celExpr: "sharenetwork.status.resource.neutronNetID == network.status.id" + - celExpr: "sharenetwork.status.resource.neutronSubnetID == subnet.status.id" + - celExpr: "sharenetwork.status.resource.projectID != ''" + - celExpr: "has(sharenetwork.status.resource.createdAt)" +# dlawton(TODO): +# Currently missing checks for networkType, segmentationID, CIDR, ipVersion, and updatedAt +# this controller will be kept as partially implemented until missing validations are included. \ No newline at end of file diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-create-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-create-resource.yaml new file mode 100644 index 000000000..7b857ba75 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-create-resource.yaml @@ -0,0 +1,42 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-create-full +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: sharenetwork-create-full-network +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-create-full +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: sharenetwork-create-full-subnet + networkRef: sharenetwork-create-full + ipVersion: 4 + cidr: 192.168.200.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-create-full +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: sharenetwork-create-full-override + description: ShareNetwork from "create full" test + networkRef: sharenetwork-create-full + subnetRef: sharenetwork-create-full diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-secret.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-full/README.md b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/README.md new file mode 100644 index 000000000..239bef04d --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-full/README.md @@ -0,0 +1,11 @@ +# Create a ShareNetwork with all the options + +## Step 00 + +Create a ShareNetwork using all available fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name from the spec when it is specified. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-assert.yaml new file mode 100644 index 000000000..67ae894a6 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-assert.yaml @@ -0,0 +1,35 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-create-minimal +status: + resource: + name: sharenetwork-create-minimal + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-create-minimal + ref: sharenetwork +assertAll: + - celExpr: "sharenetwork.status.id != ''" + - celExpr: "!has(sharenetwork.status.resource.neutronNetID)" + - celExpr: "!has(sharenetwork.status.resource.neutronSubnetID)" + - celExpr: "sharenetwork.status.resource.name == 'sharenetwork-create-minimal'" + - celExpr: "sharenetwork.status.resource.projectID != ''" + - celExpr: "has(sharenetwork.status.resource.createdAt)" + - celExpr: "has(sharenetwork.status.resource.cidr)" +# dlawton(TODO): +# Currently missing checks for networkType, segmentationID, ipVersion, and updatedAt +# this controller will be kept as partially implemented until missing validations are included. + diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-create-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-create-resource.yaml new file mode 100644 index 000000000..a0e8cd092 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-create-resource.yaml @@ -0,0 +1,10 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-secret.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/01-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/01-assert.yaml new file mode 100644 index 000000000..4912a5859 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/01-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: v1 + kind: Secret + name: openstack-clouds + ref: secret +assertAll: + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/sharenetwork' in secret.metadata.finalizers" diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/01-delete-secret.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/01-delete-secret.yaml new file mode 100644 index 000000000..1620791b9 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/01-delete-secret.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete secret openstack-clouds --wait=false + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/README.md b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/README.md new file mode 100644 index 000000000..66ca5ba8f --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-create-minimal/README.md @@ -0,0 +1,15 @@ +# Create a ShareNetwork with the minimum options + +## Step 00 + +Create a minimal ShareNetwork, that sets only the required fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified. + +## Step 01 + +Try deleting the secret and ensure that it is not deleted thanks to the finalizer. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-assert.yaml new file mode 100644 index 000000000..dfb82c2cc --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-assert.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-secret +status: + conditions: + - type: Available + message: Waiting for Secret/sharenetwork-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/sharenetwork-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-network +status: + conditions: + - type: Available + message: Waiting for Network/sharenetwork-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Network/sharenetwork-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-subnet +status: + conditions: + - type: Available + message: Waiting for Subnet/sharenetwork-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Subnet/sharenetwork-dependency to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..a47682eb6 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-dependency-no-network-available +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-dependency-no-network-available +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-dependency-no-network-available + ipVersion: 4 + cidr: 192.168.203.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-network +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-dependency + subnetRef: sharenetwork-dependency-no-network-available +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-dependency-no-subnet-available +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-subnet +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-dependency-no-subnet-available + subnetRef: sharenetwork-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-dependency-no-secret-available +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-dependency-no-secret-available +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-dependency-no-secret-available + ipVersion: 4 + cidr: 192.168.204.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-secret +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: sharenetwork-dependency + managementPolicy: managed + resource: + networkRef: sharenetwork-dependency-no-secret-available + subnetRef: sharenetwork-dependency-no-secret-available diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-secret.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/01-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/01-assert.yaml new file mode 100644 index 000000000..bfbc3944b --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/01-assert.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-secret +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-network +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-dependency-no-subnet +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/01-create-dependencies.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..a42c65d27 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/01-create-dependencies.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic sharenetwork-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-dependency +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-dependency +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-dependency + ipVersion: 4 + cidr: 192.168.202.0/24 diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/02-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/02-assert.yaml new file mode 100644 index 000000000..6ddbe841c --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/02-assert.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Network + name: sharenetwork-dependency + ref: network + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Subnet + name: sharenetwork-dependency + ref: subnet + - apiVersion: v1 + kind: Secret + name: sharenetwork-dependency + ref: secret +assertAll: + - celExpr: "network.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/sharenetwork' in network.metadata.finalizers" + - celExpr: "subnet.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/sharenetwork' in subnet.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/sharenetwork' in secret.metadata.finalizers" diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/02-delete-dependencies.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/02-delete-dependencies.yaml new file mode 100644 index 000000000..9081d277d --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/02-delete-dependencies.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete network.openstack.k-orc.cloud sharenetwork-dependency --wait=false + namespaced: true + - command: kubectl delete subnet.openstack.k-orc.cloud sharenetwork-dependency --wait=false + namespaced: true + - command: kubectl delete secret sharenetwork-dependency --wait=false + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/03-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/03-assert.yaml new file mode 100644 index 000000000..3dae927db --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/03-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get network.openstack.k-orc.cloud sharenetwork-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get subnet.openstack.k-orc.cloud sharenetwork-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret sharenetwork-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/03-delete-resources.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/03-delete-resources.yaml new file mode 100644 index 000000000..a38ca83b3 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/03-delete-resources.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-dependency-no-network +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-dependency-no-subnet diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-dependency/README.md b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/README.md new file mode 100644 index 000000000..a55d0bd35 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-dependency/README.md @@ -0,0 +1,21 @@ +# Creation and deletion dependencies + +## Step 00 + +Create ShareNetworks referencing non-existing resources. Each ShareNetwork is dependent on other non-existing resource. Verify that the ShareNetworks are waiting for the needed resources to be created externally. + +## Step 01 + +Create the missing dependencies and verify all the ShareNetworks are available. + +## Step 02 + +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 03 + +Delete the ShareNetworks and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependency diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-assert.yaml new file mode 100644 index 000000000..850cd808b --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-error-external-1 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-error-external-2 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-create-resources.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-create-resources.yaml new file mode 100644 index 000000000..849161e71 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-create-resources.yaml @@ -0,0 +1,84 @@ +--- +# Create Network for first ShareNetwork +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-import-error-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# Create Subnet for first ShareNetwork +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-import-error-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-import-error-1 + ipVersion: 4 + cidr: 192.168.207.0/24 +--- +# Create first ShareNetwork with identical description +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-error-external-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ShareNetwork from "import error" test + networkRef: sharenetwork-import-error-1 + subnetRef: sharenetwork-import-error-1 +--- +# Create Network for second ShareNetwork +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-import-error-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# Create Subnet for second ShareNetwork +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-import-error-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-import-error-2 + ipVersion: 4 + cidr: 192.168.208.0/24 +--- +# Create second ShareNetwork with identical description +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-error-external-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ShareNetwork from "import error" test + networkRef: sharenetwork-import-error-2 + subnetRef: sharenetwork-import-error-2 diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-secret.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import-error/01-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/01-assert.yaml new file mode 100644 index 000000000..817e891e7 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import-error/01-import-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/01-import-resource.yaml new file mode 100644 index 000000000..4f2ed7619 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/01-import-resource.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-error +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + description: ShareNetwork from "import error" test diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import-error/README.md b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/README.md new file mode 100644 index 000000000..209fa4a6b --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import-error/README.md @@ -0,0 +1,13 @@ +# Import ShareNetwork with more than one matching resources + +## Step 00 + +Create two ShareNetworks with identical specs. + +## Step 01 + +Ensure that an imported ShareNetwork with a filter matching the resources returns an error. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/00-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import/00-assert.yaml new file mode 100644 index 000000000..29e52d160 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/00-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing \ No newline at end of file diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/00-import-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import/00-import-resource.yaml new file mode 100644 index 000000000..fd92c10da --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/00-import-resource.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: sharenetwork-import-external + description: ShareNetwork sharenetwork-import-external from "sharenetwork-import" test diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/00-secret.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/01-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import/01-assert.yaml new file mode 100644 index 000000000..a0259a713 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/01-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-external-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: sharenetwork-import-external-not-this-one + description: ShareNetwork sharenetwork-import-external from "sharenetwork-import" test +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/01-create-trap-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..08839d2eb --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/01-create-trap-resource.yaml @@ -0,0 +1,44 @@ +--- +# Create Network for trap resource +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-import-trap +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# Create Subnet for trap resource +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-import-trap +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-import-trap + ipVersion: 4 + cidr: 192.168.205.0/24 +--- +# This `sharenetwork-import-external-not-this-one` resource serves two purposes: +# - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) +# - ensure that importing a resource which name is a substring of it will not pick this one. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ShareNetwork sharenetwork-import-external from "sharenetwork-import" test + networkRef: sharenetwork-import-trap + subnetRef: sharenetwork-import-trap diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/02-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import/02-assert.yaml new file mode 100644 index 000000000..1b60f1a48 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/02-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-import-external + ref: sharenetwork1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-import-external-not-this-one + ref: sharenetwork2 +assertAll: + - celExpr: "sharenetwork1.status.id != sharenetwork2.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: sharenetwork-import-external + description: ShareNetwork sharenetwork-import-external from "sharenetwork-import" test diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/02-create-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-import/02-create-resource.yaml new file mode 100644 index 000000000..0c753237b --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/02-create-resource.yaml @@ -0,0 +1,42 @@ +--- +# Create Network for the resource to be imported +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: sharenetwork-import-external +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# Create Subnet for the resource to be imported +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: sharenetwork-import-external +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: sharenetwork-import-external + ipVersion: 4 + cidr: 192.168.206.0/24 +--- +# Create the ShareNetwork to be imported +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-import-external +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: ShareNetwork sharenetwork-import-external from "sharenetwork-import" test + networkRef: sharenetwork-import-external + subnetRef: sharenetwork-import-external diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-import/README.md b/internal/controllers/sharenetwork/tests/sharenetwork-import/README.md new file mode 100644 index 000000000..ab1dd3733 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-import/README.md @@ -0,0 +1,18 @@ +# Import ShareNetwork + +## Step 00 + +Import a sharenetwork that matches all fields in the filter, and verify it is waiting for the external resource to be created. + +## Step 01 + +Create a sharenetwork whose name is a superstring of the one specified in the import filter, otherwise matching the filter, and verify that it's not being imported. + +## Step 02 + +Create a sharenetwork matching the filter and verify that the observed status on the imported sharenetwork corresponds to the spec of the created sharenetwork. +Also, confirm that it does not adopt any sharenetwork whose name is a superstring of its own. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/00-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-update/00-assert.yaml new file mode 100644 index 000000000..5eacdf53e --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/00-assert.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-update + ref: sharenetwork +assertAll: + - celExpr: "!has(sharenetwork.status.resource.description)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-update +status: + resource: + name: sharenetwork-update + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/00-minimal-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-update/00-minimal-resource.yaml new file mode 100644 index 000000000..13c6069c2 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/00-minimal-resource.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-update +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: {} diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/00-secret.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-update/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/01-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-update/01-assert.yaml new file mode 100644 index 000000000..a2669ad64 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/01-assert.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-update +status: + resource: + name: sharenetwork-update-updated + description: sharenetwork-update-updated + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/01-updated-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-update/01-updated-resource.yaml new file mode 100644 index 000000000..d99bfb5e6 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/01-updated-resource.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-update +spec: + resource: + name: sharenetwork-update-updated + description: sharenetwork-update-updated diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/02-assert.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-update/02-assert.yaml new file mode 100644 index 000000000..5eacdf53e --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/02-assert.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: ShareNetwork + name: sharenetwork-update + ref: sharenetwork +assertAll: + - celExpr: "!has(sharenetwork.status.resource.description)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: ShareNetwork +metadata: + name: sharenetwork-update +status: + resource: + name: sharenetwork-update + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/02-reverted-resource.yaml b/internal/controllers/sharenetwork/tests/sharenetwork-update/02-reverted-resource.yaml new file mode 100644 index 000000000..2c6c253ff --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/02-reverted-resource.yaml @@ -0,0 +1,7 @@ +# NOTE: kuttl only does patch updates, which means we can't delete a field. +# We have to use a kubectl apply command instead. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl replace -f 00-minimal-resource.yaml + namespaced: true diff --git a/internal/controllers/sharenetwork/tests/sharenetwork-update/README.md b/internal/controllers/sharenetwork/tests/sharenetwork-update/README.md new file mode 100644 index 000000000..48fbf1b56 --- /dev/null +++ b/internal/controllers/sharenetwork/tests/sharenetwork-update/README.md @@ -0,0 +1,17 @@ +# Update ShareNetwork + +## Step 00 + +Create a ShareNetwork using only mandatory fields. + +## Step 01 + +Update all mutable fields. + +## Step 02 + +Revert the resource to its original value and verify that the resulting object matches its state when first created. + +## Reference + +https://k-orc.cloud/development/writing-tests/#update diff --git a/internal/controllers/sharenetwork/zz_generated.adapter.go b/internal/controllers/sharenetwork/zz_generated.adapter.go new file mode 100644 index 000000000..a81ac97d9 --- /dev/null +++ b/internal/controllers/sharenetwork/zz_generated.adapter.go @@ -0,0 +1,98 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sharenetwork + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.ShareNetwork + orcObjectListT = orcv1alpha1.ShareNetworkList + resourceSpecT = orcv1alpha1.ShareNetworkResourceSpec + filterT = orcv1alpha1.ShareNetworkFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = sharenetworkAdapter +) + +type sharenetworkAdapter struct { + *orcv1alpha1.ShareNetwork +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.ShareNetwork +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return f.Status.ID +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.ID +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} + +// getResourceName returns the name of the OpenStack resource we should use. +// This method is not implemented as part of APIObjectAdapter as it is intended +// to be used by resource actuators, which don't use the adapter. +func getResourceName(orcObject orcObjectPT) string { + if orcObject.Spec.Resource.Name != nil { + return string(*orcObject.Spec.Resource.Name) + } + return orcObject.Name +} diff --git a/internal/controllers/sharenetwork/zz_generated.controller.go b/internal/controllers/sharenetwork/zz_generated.controller.go new file mode 100644 index 000000000..4ae4fdb2e --- /dev/null +++ b/internal/controllers/sharenetwork/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package sharenetwork + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/controllers/subnet/actuator.go b/internal/controllers/subnet/actuator.go index 951718ba6..8841a7133 100644 --- a/internal/controllers/subnet/actuator.go +++ b/internal/controllers/subnet/actuator.go @@ -37,6 +37,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" ) @@ -76,53 +77,62 @@ func (actuator subnetActuator) GetOSResourceByID(ctx context.Context, id string) } func (actuator subnetActuator) ListOSResourcesForAdoption(ctx context.Context, obj orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { - if obj.Spec.Resource == nil { + resource := obj.Spec.Resource + if resource == nil { return nil, false } - listOpts := subnets.ListOpts{Name: getResourceName(obj)} + + // Resolve the network ID from NetworkRef. Without the network ID, + // adoption could match a subnet on the wrong network. + network, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, &resource.NetworkRef, "Network", + func(dep *orcv1alpha1.Network) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + + // Resolve the project ID from ProjectRef if set. + var projectID string + if resource.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, resource.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + + listOpts := subnets.ListOpts{ + Name: getResourceName(obj), + NetworkID: ptr.Deref(network.Status.ID, ""), + CIDR: string(resource.CIDR), + IPVersion: int(resource.IPVersion), + ProjectID: projectID, + } return actuator.osClient.ListSubnet(ctx, listOpts), true } func (actuator subnetActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { var reconcileStatus progress.ReconcileStatus - network := &orcv1alpha1.Network{} - if filter.NetworkRef != "" { - networkKey := client.ObjectKey{Name: string(filter.NetworkRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, networkKey, network); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Network", networkKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching network %s: %w", networkKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(network) || network.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Network", networkKey.Name, progress.WaitingOnReady)) - } - } - } + network, rs := dependency.FetchDependency[*orcv1alpha1.Network]( + ctx, actuator.k8sClient, obj.Namespace, &filter.NetworkRef, "Network", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) - project := &orcv1alpha1.Project{} - if filter.ProjectRef != nil { - projectKey := client.ObjectKey{Name: string(*filter.ProjectRef), Namespace: obj.Namespace} - if err := actuator.k8sClient.Get(ctx, projectKey, project); err != nil { - if apierrors.IsNotFound(err) { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnCreation)) - } else { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WrapError(fmt.Errorf("fetching project %s: %w", projectKey.Name, err))) - } - } else { - if !orcv1alpha1.IsAvailable(project) || project.Status.ID == nil { - reconcileStatus = reconcileStatus.WithReconcileStatus( - progress.WaitingOnObject("Project", projectKey.Name, progress.WaitingOnReady)) - } - } - } + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus @@ -158,16 +168,12 @@ func (actuator subnetActuator) CreateResource(ctx context.Context, obj orcObject } network, reconcileStatus := networkDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Network) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) if resource.RouterRef != nil { _, routerDepRS := routerDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Router) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(routerDepRS) } @@ -175,9 +181,7 @@ func (actuator subnetActuator) CreateResource(ctx context.Context, obj orcObject var projectID string if resource.ProjectRef != nil { project, projectDepRS := projectDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.Project) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) if project != nil { @@ -243,12 +247,10 @@ func (actuator subnetActuator) CreateResource(ctx context.Context, obj orcObject osResource, err := actuator.osClient.CreateSubnet(ctx, &createOpts) - // We should require the spec to be updated before retrying a create which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } return nil, progress.WrapError(err) } return osResource, nil @@ -308,12 +310,10 @@ func (actuator subnetActuator) updateResource(ctx context.Context, obj orcObject _, err = actuator.osClient.UpdateSubnet(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/subnet/controller.go b/internal/controllers/subnet/controller.go index ea8eb33f0..b8d039dcf 100644 --- a/internal/controllers/subnet/controller.go +++ b/internal/controllers/subnet/controller.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "time" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" @@ -40,17 +41,22 @@ import ( ) type subnetReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return subnetReconcilerConstructor{scopeFactory: scopeFactory} + return &subnetReconcilerConstructor{scopeFactory: scopeFactory} } func (subnetReconcilerConstructor) GetName() string { return controllerName } +func (c *subnetReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + const controllerName = "subnet" var ( @@ -114,7 +120,7 @@ var ( ) // SetupWithManager sets up the controller with the Manager. -func (c subnetReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *subnetReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { controllerName := c.GetName() log := mgr.GetLogger().WithValues("controller", controllerName) k8sClient := mgr.GetClient() @@ -195,6 +201,6 @@ func (c subnetReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c return err } - r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, subnetHelperFactory{}, subnetStatusWriter{}) + r := reconciler.NewController(controllerName, k8sClient, c.scopeFactory, subnetHelperFactory{}, subnetStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/subnet/suite_test.go b/internal/controllers/subnet/suite_test.go index 847b93590..ec8821440 100644 --- a/internal/controllers/subnet/suite_test.go +++ b/internal/controllers/subnet/suite_test.go @@ -25,6 +25,7 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + utilrand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" @@ -82,7 +83,7 @@ var _ = Describe("EnvTest sanity check", func() { It("should be able to create a namespace", func() { ctx := context.TODO() namespace := &corev1.Namespace{} - namespace.SetGenerateName("test-") + namespace.SetName("test-" + utilrand.String(10)) // Create the namespace Expect(k8sClient.Create(ctx, namespace)).To(Succeed(), "create namespace") diff --git a/internal/controllers/subnet/zz_generated.adapter.go b/internal/controllers/subnet/zz_generated.adapter.go index 102a41b91..dedcdcf0f 100644 --- a/internal/controllers/subnet/zz_generated.adapter.go +++ b/internal/controllers/subnet/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package subnet import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/subnet/zz_generated.controller.go b/internal/controllers/subnet/zz_generated.controller.go index 58e27bae3..73fe60115 100644 --- a/internal/controllers/subnet/zz_generated.controller.go +++ b/internal/controllers/subnet/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/trunk/actuator.go b/internal/controllers/trunk/actuator.go new file mode 100644 index 000000000..f79652694 --- /dev/null +++ b/internal/controllers/trunk/actuator.go @@ -0,0 +1,460 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trunk + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags" +) + +// OpenStack resource types +type ( + osResourceT = trunks.Trunk + + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + resourceReconciler = interfaces.ResourceReconciler[orcObjectPT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) + +type trunkActuator struct { + osClient osclients.NetworkClient + k8sClient client.Client +} + +var _ createResourceActuator = trunkActuator{} +var _ deleteResourceActuator = trunkActuator{} + +func (trunkActuator) GetResourceID(osResource *osResourceT) string { + return osResource.ID +} + +func (actuator trunkActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) { + resource, err := actuator.osClient.GetTrunk(ctx, id) + if err != nil { + return nil, progress.WrapError(err) + } + return resource, nil +} + +func (actuator trunkActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + // Resolve the port ID from PortRef. Without the port ID, adoption + // could match a trunk associated with the wrong parent port. + port, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, &resourceSpec.PortRef, "Port", + func(dep *orcv1alpha1.Port) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + + // Resolve the project ID from ProjectRef if set. + var projectID string + if resourceSpec.ProjectRef != nil { + project, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.ProjectRef, "Project", + func(dep *orcv1alpha1.Project) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + projectID = ptr.Deref(project.Status.ID, "") + } + + listOpts := trunks.ListOpts{ + Name: getResourceName(orcObject), + Description: string(ptr.Deref(resourceSpec.Description, "")), + PortID: ptr.Deref(port.Status.ID, ""), + ProjectID: projectID, + } + + return actuator.osClient.ListTrunks(ctx, listOpts), true +} + +func (actuator trunkActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + port, rs := dependency.FetchDependency[*orcv1alpha1.Port]( + ctx, actuator.k8sClient, obj.Namespace, + filter.PortRef, "Port", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + project, rs := dependency.FetchDependency[*orcv1alpha1.Project]( + ctx, actuator.k8sClient, obj.Namespace, + filter.ProjectRef, "Project", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + listOpts := trunks.ListOpts{ + Name: string(ptr.Deref(filter.Name, "")), + Description: string(ptr.Deref(filter.Description, "")), + PortID: ptr.Deref(port.Status.ID, ""), + ProjectID: ptr.Deref(project.Status.ID, ""), + AdminStateUp: filter.AdminStateUp, + Tags: tags.Join(filter.Tags), + TagsAny: tags.Join(filter.TagsAny), + NotTags: tags.Join(filter.NotTags), + NotTagsAny: tags.Join(filter.NotTagsAny), + } + + return actuator.osClient.ListTrunks(ctx, listOpts), reconcileStatus +} + +func (actuator trunkActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + var reconcileStatus progress.ReconcileStatus + + var portID string + port, portDepRS := portDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(portDepRS) + if port != nil { + portID = ptr.Deref(port.Status.ID, "") + } + + var projectID string + if resource.ProjectRef != nil { + project, projectDepRS := projectDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) + if project != nil { + projectID = ptr.Deref(project.Status.ID, "") + } + } + + // Resolve subport port dependencies + var subports []trunks.Subport + if len(resource.Subports) > 0 { + subportPortMap, subportPortDepRS := subportPortDependency.GetDependencies( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(subportPortDepRS) + if needsReschedule, _ := subportPortDepRS.NeedsReschedule(); !needsReschedule { + subports = make([]trunks.Subport, len(resource.Subports)) + for i := range resource.Subports { + subportSpec := &resource.Subports[i] + port, ok := subportPortMap[string(subportSpec.PortRef)] + if !ok { + return nil, reconcileStatus.WithError(fmt.Errorf("unable to resolve required subport port reference: %s", subportSpec.PortRef)) + } + subports[i] = trunks.Subport{ + PortID: ptr.Deref(port.Status.ID, ""), + SegmentationID: int(subportSpec.SegmentationID), + SegmentationType: subportSpec.SegmentationType, + } + } + } + } + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + createOpts := trunks.CreateOpts{ + Name: getResourceName(obj), + Description: string(ptr.Deref(resource.Description, "")), + PortID: portID, + ProjectID: projectID, + AdminStateUp: resource.AdminStateUp, + Subports: subports, + } + + osResource, err := actuator.osClient.CreateTrunk(ctx, createOpts) + if err != nil { + // We should require the spec to be updated before retrying a create which returned a conflict + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + return osResource, nil +} + +func (actuator trunkActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + return progress.WrapError(actuator.osClient.DeleteTrunk(ctx, resource.ID)) +} + +func (actuator trunkActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + // Should have been caught by API validation + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + + updateOpts := trunks.UpdateOpts{} + + handleNameUpdate(&updateOpts, obj, osResource) + handleDescriptionUpdate(&updateOpts, resource, osResource) + handleAdminStateUpUpdate(&updateOpts, resource, osResource) + + needsUpdate, err := needsUpdate(updateOpts) + if err != nil { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err)) + } + if !needsUpdate { + log.V(logging.Debug).Info("No changes") + return nil + } + + _, err = actuator.osClient.UpdateTrunk(ctx, osResource.ID, updateOpts) + + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) + } + + return progress.NeedsRefresh() +} + +func needsUpdate(updateOpts trunks.UpdateOpts) (bool, error) { + updateOptsMap, err := updateOpts.ToTrunkUpdateMap() + if err != nil { + return false, err + } + + updateMap, ok := updateOptsMap["trunk"].(map[string]any) + if !ok { + updateMap = make(map[string]any) + } + + return len(updateMap) > 0, nil +} + +func handleNameUpdate(updateOpts *trunks.UpdateOpts, obj orcObjectPT, osResource *osResourceT) { + name := getResourceName(obj) + if osResource.Name != name { + updateOpts.Name = &name + } +} + +func handleDescriptionUpdate(updateOpts *trunks.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + description := string(ptr.Deref(resource.Description, "")) + if osResource.Description != description { + updateOpts.Description = &description + } +} + +func handleAdminStateUpUpdate(updateOpts *trunks.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + // Default is true + adminStateUp := ptr.Deref(resource.AdminStateUp, true) + if osResource.AdminStateUp != adminStateUp { + updateOpts.AdminStateUp = &adminStateUp + } +} + +func (actuator trunkActuator) reconcileSubports(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + return nil + } + + var reconcileStatus progress.ReconcileStatus + + // Build desired subports map: portID -> subport spec + desiredSubports := make(map[string]*orcv1alpha1.TrunkSubportSpec, len(osResource.Subports)) + if len(resource.Subports) > 0 { + subportPortMap, subportPortDepRS := subportPortDependency.GetDependencies( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(subportPortDepRS) + if needsReschedule, _ := subportPortDepRS.NeedsReschedule(); needsReschedule { + return reconcileStatus + } + + for i := range resource.Subports { + subportSpec := &resource.Subports[i] + port, ok := subportPortMap[string(subportSpec.PortRef)] + if !ok { + return reconcileStatus.WithError(fmt.Errorf("unable to resolve required subport port reference: %s", subportSpec.PortRef)) + } + portID := ptr.Deref(port.Status.ID, "") + if portID == "" { + return reconcileStatus.WithError(fmt.Errorf("subport port %s does not have an ID", subportSpec.PortRef)) + } + desiredSubports[portID] = subportSpec + } + } + + // Build actual subports map: portID -> subport + actualSubports := make(map[string]trunks.Subport) + for i := range osResource.Subports { + sp := osResource.Subports[i] + actualSubports[sp.PortID] = sp + } + + // Determine subports to add and remove + var subportsToAdd []trunks.Subport + var subportsToRemove []trunks.RemoveSubport + + // Find subports to add (in desired but not in actual, or different segmentation) + for portID, desiredSpec := range desiredSubports { + actual, exists := actualSubports[portID] + if !exists { + // Need to add this subport + subportsToAdd = append(subportsToAdd, trunks.Subport{ + PortID: portID, + SegmentationID: int(desiredSpec.SegmentationID), + SegmentationType: desiredSpec.SegmentationType, + }) + } else if actual.SegmentationID != int(desiredSpec.SegmentationID) || actual.SegmentationType != desiredSpec.SegmentationType { + // Segmentation changed - need to remove and re-add + subportsToRemove = append(subportsToRemove, trunks.RemoveSubport{PortID: portID}) + subportsToAdd = append(subportsToAdd, trunks.Subport{ + PortID: portID, + SegmentationID: int(desiredSpec.SegmentationID), + SegmentationType: desiredSpec.SegmentationType, + }) + } + } + + // Find subports to remove (in actual but not in desired) + for portID := range actualSubports { + if _, exists := desiredSubports[portID]; !exists { + subportsToRemove = append(subportsToRemove, trunks.RemoveSubport{PortID: portID}) + } + } + + // Apply changes - remove first, then add + // This ensures that if we're updating a subport (remove + add), the remove happens first + if len(subportsToRemove) > 0 { + log.V(logging.Debug).Info("Removing subports", "count", len(subportsToRemove)) + removeOpts := trunks.RemoveSubportsOpts{ + Subports: subportsToRemove, + } + if err := actuator.osClient.RemoveSubports(ctx, osResource.ID, removeOpts); err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration removing subports: "+err.Error(), err) + } + return reconcileStatus.WithError(err) + } + // Always refresh after removing subports, especially if we're also adding some + reconcileStatus = reconcileStatus.WithReconcileStatus(progress.NeedsRefresh()) + } + if len(subportsToAdd) > 0 { + log.V(logging.Debug).Info("Adding subports", "count", len(subportsToAdd)) + addOpts := trunks.AddSubportsOpts{ + Subports: subportsToAdd, + } + if _, err := actuator.osClient.AddSubports(ctx, osResource.ID, addOpts); err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration adding subports: "+err.Error(), err) + } + return reconcileStatus.WithError(err) + } + reconcileStatus = reconcileStatus.WithReconcileStatus(progress.NeedsRefresh()) + } + + if len(subportsToAdd) == 0 && len(subportsToRemove) == 0 { + log.V(logging.Debug).Info("No subport changes") + } + + return reconcileStatus +} + +func (actuator trunkActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + tags.ReconcileTags[orcObjectPT, osResourceT](orcObject.Spec.Resource.Tags, osResource.Tags, tags.NewNeutronTagReplacer(actuator.osClient, "trunks", osResource.ID)), + actuator.reconcileSubports, + actuator.updateResource, + }, nil +} + +type trunkHelperFactory struct{} + +var _ helperFactory = trunkHelperFactory{} + +func newActuator(ctx context.Context, orcObject *orcv1alpha1.Trunk, controller interfaces.ResourceController) (trunkActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, controller.GetK8sClient(), orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return trunkActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject) + if err != nil { + return trunkActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewNetworkClient() + if err != nil { + return trunkActuator{}, progress.WrapError(err) + } + + return trunkActuator{ + osClient: osClient, + k8sClient: controller.GetK8sClient(), + }, nil +} + +func (trunkHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { + return trunkAdapter{obj} +} + +func (trunkHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} + +func (trunkHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} diff --git a/internal/controllers/trunk/actuator_test.go b/internal/controllers/trunk/actuator_test.go new file mode 100644 index 000000000..aa2981fa6 --- /dev/null +++ b/internal/controllers/trunk/actuator_test.go @@ -0,0 +1,332 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trunk + +import ( + "slices" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "k8s.io/utils/ptr" +) + +func TestNeedsUpdate(t *testing.T) { + testCases := []struct { + name string + updateOpts trunks.UpdateOpts + expectChange bool + }{ + { + name: "Empty base opts", + updateOpts: trunks.UpdateOpts{}, + expectChange: false, + }, + { + name: "Updated opts", + updateOpts: trunks.UpdateOpts{Name: ptr.To("updated")}, + expectChange: true, + }, + { + name: "RevisionNumber only should not require update", + updateOpts: trunks.UpdateOpts{RevisionNumber: ptr.To(10)}, + expectChange: false, + }, + { + name: "Name + RevisionNumber should require update", + updateOpts: trunks.UpdateOpts{Name: ptr.To("updated"), RevisionNumber: ptr.To(10)}, + expectChange: true, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + got, _ := needsUpdate(tt.updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestHandleNameUpdate(t *testing.T) { + ptrToName := ptr.To[orcv1alpha1.OpenStackName] + testCases := []struct { + name string + newValue *orcv1alpha1.OpenStackName + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToName("name"), existingValue: "name", expectChange: false}, + {name: "Different", newValue: ptrToName("new-name"), existingValue: "name", expectChange: true}, + {name: "No value provided, existing is identical to object name", newValue: nil, existingValue: "object-name", expectChange: false}, + {name: "No value provided, existing is different from object name", newValue: nil, existingValue: "different-from-object-name", expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.Trunk{} + resource.Name = "object-name" + resource.Spec = orcv1alpha1.TrunkSpec{ + Resource: &orcv1alpha1.TrunkResourceSpec{Name: tt.newValue}, + } + osResource := &osResourceT{Name: tt.existingValue} + + updateOpts := trunks.UpdateOpts{} + handleNameUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleDescriptionUpdate(t *testing.T) { + ptrToDescription := ptr.To[orcv1alpha1.NeutronDescription] + testCases := []struct { + name string + newValue *orcv1alpha1.NeutronDescription + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToDescription("desc"), existingValue: "desc", expectChange: false}, + {name: "Different", newValue: ptrToDescription("new-desc"), existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is set", newValue: nil, existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is empty", newValue: nil, existingValue: "", expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.TrunkResourceSpec{Description: tt.newValue} + osResource := &osResourceT{Description: tt.existingValue} + + updateOpts := trunks.UpdateOpts{} + handleDescriptionUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleAdminStateUpUpdate(t *testing.T) { + ptrToBool := ptr.To[bool] + testCases := []struct { + name string + newValue *bool + existingValue bool + expectChange bool + }{ + {name: "Identical true", newValue: ptrToBool(true), existingValue: true, expectChange: false}, + {name: "Identical false", newValue: ptrToBool(false), existingValue: false, expectChange: false}, + {name: "Different (true -> false)", newValue: ptrToBool(false), existingValue: true, expectChange: true}, + {name: "Different (false -> true)", newValue: ptrToBool(true), existingValue: false, expectChange: true}, + {name: "Nil means default true (existing true)", newValue: nil, existingValue: true, expectChange: false}, + {name: "Nil means default true (existing false)", newValue: nil, existingValue: false, expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.TrunkResourceSpec{AdminStateUp: tt.newValue} + osResource := &osResourceT{AdminStateUp: tt.existingValue} + + updateOpts := trunks.UpdateOpts{} + handleAdminStateUpUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestReconcileSubportsLogic(t *testing.T) { + testCases := []struct { + name string + desiredSubports map[string]*orcv1alpha1.TrunkSubportSpec + actualSubports map[string]trunks.Subport + expectedSubportsToAdd []trunks.Subport + expectedSubportsRemove []trunks.Subport + }{ + { + name: "No changes needed", + desiredSubports: map[string]*orcv1alpha1.TrunkSubportSpec{ + "port1": {SegmentationID: 100, SegmentationType: "vlan"}, + }, + actualSubports: map[string]trunks.Subport{ + "port1": {PortID: "port1", SegmentationID: 100, SegmentationType: "vlan"}, + }, + expectedSubportsToAdd: []trunks.Subport{}, + expectedSubportsRemove: []trunks.Subport{}, + }, + { + name: "Add new subport", + desiredSubports: map[string]*orcv1alpha1.TrunkSubportSpec{ + "port1": {SegmentationID: 100, SegmentationType: "vlan"}, + "port2": {SegmentationID: 200, SegmentationType: "vlan"}, + }, + actualSubports: map[string]trunks.Subport{ + "port1": {PortID: "port1", SegmentationID: 100, SegmentationType: "vlan"}, + }, + expectedSubportsToAdd: []trunks.Subport{ + {PortID: "port2", SegmentationID: 200, SegmentationType: "vlan"}, + }, + expectedSubportsRemove: []trunks.Subport{}, + }, + { + name: "Remove subport", + desiredSubports: map[string]*orcv1alpha1.TrunkSubportSpec{ + "port1": {SegmentationID: 100, SegmentationType: "vlan"}, + }, + actualSubports: map[string]trunks.Subport{ + "port1": {PortID: "port1", SegmentationID: 100, SegmentationType: "vlan"}, + "port2": {PortID: "port2", SegmentationID: 200, SegmentationType: "vlan"}, + }, + expectedSubportsToAdd: []trunks.Subport{}, + expectedSubportsRemove: []trunks.Subport{ + {PortID: "port2"}, + }, + }, + { + name: "Update segmentation", + desiredSubports: map[string]*orcv1alpha1.TrunkSubportSpec{ + "port1": {SegmentationID: 150, SegmentationType: "vlan"}, + }, + actualSubports: map[string]trunks.Subport{ + "port1": {PortID: "port1", SegmentationID: 100, SegmentationType: "vlan"}, + }, + expectedSubportsToAdd: []trunks.Subport{ + {PortID: "port1", SegmentationID: 150, SegmentationType: "vlan"}, + }, + expectedSubportsRemove: []trunks.Subport{ + {PortID: "port1"}, + }, + }, + { + name: "Update segmentation type", + desiredSubports: map[string]*orcv1alpha1.TrunkSubportSpec{ + "port1": {SegmentationID: 100, SegmentationType: "inherit"}, + }, + actualSubports: map[string]trunks.Subport{ + "port1": {PortID: "port1", SegmentationID: 100, SegmentationType: "vlan"}, + }, + expectedSubportsToAdd: []trunks.Subport{ + {PortID: "port1", SegmentationID: 100, SegmentationType: "inherit"}, + }, + expectedSubportsRemove: []trunks.Subport{ + {PortID: "port1"}, + }, + }, + { + name: "Remove all subports", + desiredSubports: map[string]*orcv1alpha1.TrunkSubportSpec{}, + actualSubports: map[string]trunks.Subport{ + "port1": {PortID: "port1", SegmentationID: 100, SegmentationType: "vlan"}, + "port2": {PortID: "port2", SegmentationID: 200, SegmentationType: "vlan"}, + }, + expectedSubportsToAdd: []trunks.Subport{}, + expectedSubportsRemove: []trunks.Subport{ + {PortID: "port1"}, + {PortID: "port2"}, + }, + }, + { + name: "Complex update: add, remove, and modify", + desiredSubports: map[string]*orcv1alpha1.TrunkSubportSpec{ + "port1": {SegmentationID: 150, SegmentationType: "vlan"}, // modified + "port3": {SegmentationID: 300, SegmentationType: "vlan"}, // new + }, + actualSubports: map[string]trunks.Subport{ + "port1": {PortID: "port1", SegmentationID: 100, SegmentationType: "vlan"}, + "port2": {PortID: "port2", SegmentationID: 200, SegmentationType: "vlan"}, // removed + }, + expectedSubportsToAdd: []trunks.Subport{ + {PortID: "port1", SegmentationID: 150, SegmentationType: "vlan"}, // modified + {PortID: "port3", SegmentationID: 300, SegmentationType: "vlan"}, // new + }, + expectedSubportsRemove: []trunks.Subport{ + {PortID: "port1"}, // for modification + {PortID: "port2"}, // removed + }, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + subportsToAdd := []trunks.Subport{} + subportsToRemove := []trunks.Subport{} + + // Find subports to add (in desired but not in actual, or different segmentation) + for portID, desiredSpec := range tt.desiredSubports { + actual, exists := tt.actualSubports[portID] + if !exists { + // Need to add this subport + subportsToAdd = append(subportsToAdd, trunks.Subport{ + PortID: portID, + SegmentationID: int(desiredSpec.SegmentationID), + SegmentationType: desiredSpec.SegmentationType, + }) + } else if actual.SegmentationID != int(desiredSpec.SegmentationID) || actual.SegmentationType != desiredSpec.SegmentationType { + // Segmentation changed - need to remove and re-add + subportsToRemove = append(subportsToRemove, trunks.Subport{PortID: portID}) + subportsToAdd = append(subportsToAdd, trunks.Subport{ + PortID: portID, + SegmentationID: int(desiredSpec.SegmentationID), + SegmentationType: desiredSpec.SegmentationType, + }) + } + } + + // Find subports to remove (in actual but not in desired) + for portID := range tt.actualSubports { + if _, exists := tt.desiredSubports[portID]; !exists { + subportsToRemove = append(subportsToRemove, trunks.Subport{PortID: portID}) + } + } + + // Sort slices by PortID for deterministic comparison + sortByPortID := func(a, b trunks.Subport) int { + if a.PortID < b.PortID { + return -1 + } + if a.PortID > b.PortID { + return 1 + } + return 0 + } + slices.SortFunc(subportsToAdd, sortByPortID) + slices.SortFunc(subportsToRemove, sortByPortID) + slices.SortFunc(tt.expectedSubportsToAdd, sortByPortID) + slices.SortFunc(tt.expectedSubportsRemove, sortByPortID) + + if diff := cmp.Diff(tt.expectedSubportsToAdd, subportsToAdd); diff != "" { + t.Errorf("Subports to add mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(tt.expectedSubportsRemove, subportsToRemove); diff != "" { + t.Errorf("Subports to remove mismatch (-want +got):\n%s", diff) + } + }) + } +} diff --git a/internal/controllers/trunk/controller.go b/internal/controllers/trunk/controller.go new file mode 100644 index 000000000..95b0c23a2 --- /dev/null +++ b/internal/controllers/trunk/controller.go @@ -0,0 +1,193 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trunk + +import ( + "context" + "errors" + "time" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "trunk" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=trunks,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=trunks/status,verbs=get;update;patch + +type trunkReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return &trunkReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (trunkReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *trunkReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var portDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.TrunkList, *orcv1alpha1.Port]( + "spec.resource.portRef", + func(trunk *orcv1alpha1.Trunk) []string { + resource := trunk.Spec.Resource + if resource == nil { + return nil + } + return []string{string(resource.PortRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var projectDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.TrunkList, *orcv1alpha1.Project]( + "spec.resource.projectRef", + func(trunk *orcv1alpha1.Trunk) []string { + resource := trunk.Spec.Resource + if resource == nil || resource.ProjectRef == nil { + return nil + } + return []string{string(*resource.ProjectRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var portImportDependency = dependency.NewDependency[*orcv1alpha1.TrunkList, *orcv1alpha1.Port]( + "spec.import.filter.portRef", + func(trunk *orcv1alpha1.Trunk) []string { + resource := trunk.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.PortRef == nil { + return nil + } + return []string{string(*resource.Filter.PortRef)} + }, +) + +var projectImportDependency = dependency.NewDependency[*orcv1alpha1.TrunkList, *orcv1alpha1.Project]( + "spec.import.filter.projectRef", + func(trunk *orcv1alpha1.Trunk) []string { + resource := trunk.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.ProjectRef == nil { + return nil + } + return []string{string(*resource.Filter.ProjectRef)} + }, +) + +var subportPortDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.TrunkList, *orcv1alpha1.Port]( + "spec.resource.subports[].portRef", + func(trunk *orcv1alpha1.Trunk) []string { + resource := trunk.Spec.Resource + if resource == nil { + return nil + } + if len(resource.Subports) == 0 { + return nil + } + portRefs := make([]string, 0, len(resource.Subports)) + for i := range resource.Subports { + portRefs = append(portRefs, string(resource.Subports[i].PortRef)) + } + return portRefs + }, + orcstrings.GetFinalizerName("trunk-subport"), externalObjectFieldOwner, + dependency.OverrideDependencyName("subport_port"), +) + +// SetupWithManager sets up the controller with the Manager. +func (c *trunkReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + portWatchEventHandler, err := portDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + projectWatchEventHandler, err := projectDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + portImportWatchEventHandler, err := portImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + projectImportWatchEventHandler, err := projectImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + subportPortWatchEventHandler, err := subportPortDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + Watches(&orcv1alpha1.Port{}, portWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Port{})), + ). + Watches(&orcv1alpha1.Project{}, projectWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Port{}, portImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Port{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Project{}, projectImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ). + // Watch for subport port changes + Watches(&orcv1alpha1.Port{}, subportPortWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Port{})), + ). + For(&orcv1alpha1.Trunk{}) + + if err := errors.Join( + portDependency.AddToManager(ctx, mgr), + projectDependency.AddToManager(ctx, mgr), + portImportDependency.AddToManager(ctx, mgr), + projectImportDependency.AddToManager(ctx, mgr), + subportPortDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, trunkHelperFactory{}, trunkStatusWriter{}, c.defaultResyncPeriod) + return builder.Complete(&r) +} diff --git a/internal/controllers/trunk/status.go b/internal/controllers/trunk/status.go new file mode 100644 index 000000000..8ff307cdc --- /dev/null +++ b/internal/controllers/trunk/status.go @@ -0,0 +1,92 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trunk + +import ( + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type trunkStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.TrunkApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.TrunkStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.Trunk, *osResourceT, *objectApplyT, *statusApplyT] = trunkStatusWriter{} + +func (trunkStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.Trunk(name, namespace) +} + +func (trunkStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.Trunk, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource == nil { + if orcObject.Status.ID == nil { + return metav1.ConditionFalse, nil + } else { + return metav1.ConditionUnknown, nil + } + } + return metav1.ConditionTrue, nil +} + +func (trunkStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.TrunkResourceStatus(). + WithPortID(osResource.PortID). + WithProjectID(osResource.ProjectID). + WithName(osResource.Name). + WithAdminStateUp(osResource.AdminStateUp). + WithRevisionNumber(int64(osResource.RevisionNumber)). + WithCreatedAt(metav1.NewTime(osResource.CreatedAt)). + WithUpdatedAt(metav1.NewTime(osResource.UpdatedAt)) + + if osResource.Status != "" { + resourceStatus.WithStatus(osResource.Status) + } + + if osResource.TenantID != "" { + resourceStatus.WithTenantID(osResource.TenantID) + } + + if len(osResource.Tags) > 0 { + resourceStatus.WithTags(osResource.Tags...) + } + + if len(osResource.Subports) > 0 { + subports := make([]*orcapplyconfigv1alpha1.TrunkSubportStatusApplyConfiguration, 0, len(osResource.Subports)) + for i := range osResource.Subports { + sp := osResource.Subports[i] + subports = append(subports, + orcapplyconfigv1alpha1.TrunkSubportStatus(). + WithPortID(sp.PortID). + WithSegmentationID(int32(sp.SegmentationID)). + WithSegmentationType(sp.SegmentationType), + ) + } + resourceStatus.WithSubports(subports...) + } + + if osResource.Description != "" { + resourceStatus.WithDescription(osResource.Description) + } + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/trunk/tests/trunk-create-full/00-assert.yaml b/internal/controllers/trunk/tests/trunk-create-full/00-assert.yaml new file mode 100644 index 000000000..cac1ea281 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-full/00-assert.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-create-full +status: + resource: + name: trunk-create-full-override + description: Trunk from "create full" test + adminStateUp: false + status: ACTIVE + tags: + - tag1 + - tag2 + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-create-full + ref: trunk + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-create-full + ref: port + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-create-full-subport1 + ref: subport1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-create-full-subport2 + ref: subport2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: trunk-create-full + ref: project +assertAll: + - celExpr: "trunk.status.id != ''" + - celExpr: "trunk.status.resource.portID == port.status.id" + - celExpr: "trunk.status.resource.projectID == project.status.id" + - celExpr: "trunk.status.resource.tenantID != ''" + - celExpr: "trunk.status.resource.createdAt != ''" + - celExpr: "trunk.status.resource.updatedAt != ''" + - celExpr: "trunk.status.resource.revisionNumber > 0" + - celExpr: "trunk.status.resource.subports.size() == 2" + - celExpr: "trunk.status.resource.subports.exists(s, s.portID == subport1.status.id && s.segmentationID == 100 && s.segmentationType == 'vlan')" + - celExpr: "trunk.status.resource.subports.exists(s, s.portID == subport2.status.id && s.segmentationID == 200 && s.segmentationType == 'vlan')" diff --git a/internal/controllers/trunk/tests/trunk-create-full/00-create-resource.yaml b/internal/controllers/trunk/tests/trunk-create-full/00-create-resource.yaml new file mode 100644 index 000000000..52e9e7ab7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-full/00-create-resource.yaml @@ -0,0 +1,101 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: trunk-create-full +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-create-full +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: trunk-create-full +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-create-full + ipVersion: 4 + cidr: 192.168.158.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-create-full +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-create-full + addresses: + - subnetRef: trunk-create-full +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-create-full-subport1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-create-full +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-create-full-subport2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-create-full +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: trunk-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-create-full-override + description: Trunk from "create full" test + adminStateUp: false + portRef: trunk-create-full + projectRef: trunk-create-full + subports: + - portRef: trunk-create-full-subport1 + segmentationID: 100 + segmentationType: vlan + - portRef: trunk-create-full-subport2 + segmentationID: 200 + segmentationType: vlan + tags: + - tag1 + - tag2 diff --git a/internal/controllers/trunk/tests/trunk-create-full/00-secret.yaml b/internal/controllers/trunk/tests/trunk-create-full/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-full/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-create-full/01-assert.yaml b/internal/controllers/trunk/tests/trunk-create-full/01-assert.yaml new file mode 100644 index 000000000..cd2aea264 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-full/01-assert.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-create-full +status: + resource: + adminStateUp: true diff --git a/internal/controllers/trunk/tests/trunk-create-full/01-set-adminstateup.yaml b/internal/controllers/trunk/tests/trunk-create-full/01-set-adminstateup.yaml new file mode 100644 index 000000000..35b1c16d5 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-full/01-set-adminstateup.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-create-full +spec: + resource: + adminStateUp: true diff --git a/internal/controllers/trunk/tests/trunk-create-full/README.md b/internal/controllers/trunk/tests/trunk-create-full/README.md new file mode 100644 index 000000000..b09578791 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-full/README.md @@ -0,0 +1,15 @@ +# Create a Trunk with all the options + +## Step 00 + +Create a Trunk using all available fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name from the spec when it is specified. + +## Step 01 + +By default neutron refuses to delete disabled trunks. This step sets the `AdminStateUp` accordingly so that we can delete the trunk. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/trunk/tests/trunk-create-minimal/00-assert.yaml b/internal/controllers/trunk/tests/trunk-create-minimal/00-assert.yaml new file mode 100644 index 000000000..0a90e0c7f --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-minimal/00-assert.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-create-minimal +status: + resource: + name: trunk-create-minimal + adminStateUp: true + status: ACTIVE + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-create-minimal + ref: trunk + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-create-minimal + ref: port +assertAll: + - celExpr: "trunk.status.id != ''" + - celExpr: "trunk.status.resource.portID == port.status.id" + - celExpr: "trunk.status.resource.projectID != ''" + - celExpr: "trunk.status.resource.tenantID != ''" + - celExpr: "trunk.status.resource.createdAt != ''" + - celExpr: "trunk.status.resource.updatedAt != ''" + - celExpr: "trunk.status.resource.revisionNumber > 0" + - celExpr: "!has(trunk.status.resource.description)" + - celExpr: "!has(trunk.status.resource.tags)" + - celExpr: "!has(trunk.status.resource.subports)" diff --git a/internal/controllers/trunk/tests/trunk-create-minimal/00-create-resource.yaml b/internal/controllers/trunk/tests/trunk-create-minimal/00-create-resource.yaml new file mode 100644 index 000000000..c3cc20990 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-minimal/00-create-resource.yaml @@ -0,0 +1,52 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: trunk-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-create-minimal +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: trunk-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-create-minimal + ipVersion: 4 + cidr: 192.168.156.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-create-minimal + addresses: + - subnetRef: trunk-create-minimal +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + portRef: trunk-create-minimal diff --git a/internal/controllers/trunk/tests/trunk-create-minimal/00-secret.yaml b/internal/controllers/trunk/tests/trunk-create-minimal/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-minimal/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-create-minimal/01-assert.yaml b/internal/controllers/trunk/tests/trunk-create-minimal/01-assert.yaml new file mode 100644 index 000000000..35eab2add --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-minimal/01-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: v1 + kind: Secret + name: openstack-clouds + ref: secret +assertAll: + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/trunk' in secret.metadata.finalizers" diff --git a/internal/controllers/trunk/tests/trunk-create-minimal/01-delete-secret.yaml b/internal/controllers/trunk/tests/trunk-create-minimal/01-delete-secret.yaml new file mode 100644 index 000000000..1620791b9 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-minimal/01-delete-secret.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete secret openstack-clouds --wait=false + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-create-minimal/README.md b/internal/controllers/trunk/tests/trunk-create-minimal/README.md new file mode 100644 index 000000000..49a8df75e --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-create-minimal/README.md @@ -0,0 +1,15 @@ +# Create a Trunk with the minimum options + +## Step 00 + +Create a minimal Trunk, that sets only the required fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified. + +## Step 01 + +Try deleting the secret and ensure that it is not deleted thanks to the finalizer. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/trunk/tests/trunk-dependency/00-assert.yaml b/internal/controllers/trunk/tests/trunk-dependency/00-assert.yaml new file mode 100644 index 000000000..62cf47bac --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/00-assert.yaml @@ -0,0 +1,60 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-secret +status: + conditions: + - type: Available + message: Waiting for Secret/trunk-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/trunk-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-port +status: + conditions: + - type: Available + message: Waiting for Port/trunk-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Port/trunk-dependency-pending to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-subport +status: + conditions: + - type: Available + message: Waiting for Port/trunk-dependency-subport-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Port/trunk-dependency-subport-pending to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-project +status: + conditions: + - type: Available + message: Waiting for Project/trunk-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Project/trunk-dependency to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/trunk/tests/trunk-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/trunk/tests/trunk-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..78a4a4c4c --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,121 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: trunk-dependency +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: trunk-dependency +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + cidr: 192.168.160.0/24 + ipVersion: 4 + networkRef: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-dependency-parent-no-subport +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-dependency + addresses: + - subnetRef: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-dependency-parent-no-project +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-dependency + addresses: + - subnetRef: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-dependency-parent-no-secret +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-dependency + addresses: + - subnetRef: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-port +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + portRef: trunk-dependency-pending +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-subport +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + portRef: trunk-dependency-parent-no-subport + subports: + - portRef: trunk-dependency-subport-pending + segmentationID: 100 + segmentationType: vlan +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + portRef: trunk-dependency-parent-no-project + projectRef: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-secret +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: trunk-dependency + managementPolicy: managed + resource: + portRef: trunk-dependency-parent-no-secret diff --git a/internal/controllers/trunk/tests/trunk-dependency/00-secret.yaml b/internal/controllers/trunk/tests/trunk-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-dependency/01-assert.yaml b/internal/controllers/trunk/tests/trunk-dependency/01-assert.yaml new file mode 100644 index 000000000..c7a7be2a2 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/01-assert.yaml @@ -0,0 +1,60 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-secret +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-port +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-subport +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-dependency-no-project +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/trunk/tests/trunk-dependency/01-create-dependencies.yaml b/internal/controllers/trunk/tests/trunk-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..2359632d2 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/01-create-dependencies.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic trunk-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-dependency-pending +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-dependency + addresses: + - subnetRef: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-dependency-subport-pending +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-dependency + addresses: + - subnetRef: trunk-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: trunk-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} diff --git a/internal/controllers/trunk/tests/trunk-dependency/02-assert.yaml b/internal/controllers/trunk/tests/trunk-dependency/02-assert.yaml new file mode 100644 index 000000000..4b1e7d9e1 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/02-assert.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-dependency-pending + ref: port + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-dependency-subport-pending + ref: subport + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: trunk-dependency + ref: project + - apiVersion: v1 + kind: Secret + name: trunk-dependency + ref: secret +assertAll: + - celExpr: "port.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/trunk' in port.metadata.finalizers" + - celExpr: "subport.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/trunk-subport' in subport.metadata.finalizers" + - celExpr: "project.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/trunk' in project.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/trunk' in secret.metadata.finalizers" diff --git a/internal/controllers/trunk/tests/trunk-dependency/02-delete-dependencies.yaml b/internal/controllers/trunk/tests/trunk-dependency/02-delete-dependencies.yaml new file mode 100644 index 000000000..0a4b8702f --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/02-delete-dependencies.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete port.openstack.k-orc.cloud trunk-dependency-pending --wait=false + namespaced: true + - command: kubectl delete port.openstack.k-orc.cloud trunk-dependency-subport-pending --wait=false + namespaced: true + - command: kubectl delete project.openstack.k-orc.cloud trunk-dependency --wait=false + namespaced: true + - command: kubectl delete secret trunk-dependency --wait=false + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-dependency/03-assert.yaml b/internal/controllers/trunk/tests/trunk-dependency/03-assert.yaml new file mode 100644 index 000000000..c334998c2 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/03-assert.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get port.openstack.k-orc.cloud trunk-dependency-pending --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get port.openstack.k-orc.cloud trunk-dependency-subport-pending --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get project.openstack.k-orc.cloud trunk-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret trunk-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/trunk/tests/trunk-dependency/03-delete-resources.yaml b/internal/controllers/trunk/tests/trunk-dependency/03-delete-resources.yaml new file mode 100644 index 000000000..c54f12587 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/03-delete-resources.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-dependency-no-port +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-dependency-no-subport +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-dependency-no-project diff --git a/internal/controllers/trunk/tests/trunk-dependency/README.md b/internal/controllers/trunk/tests/trunk-dependency/README.md new file mode 100644 index 000000000..14d0a8ec4 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-dependency/README.md @@ -0,0 +1,21 @@ +# Creation and deletion dependencies + +## Step 00 + +Create Trunks referencing non-existing resources. Each Trunk is dependent on other non-existing resource. Verify that the Trunks are waiting for the needed resources to be created externally. + +## Step 01 + +Create the missing dependencies and verify all the Trunks are available. + +## Step 02 + +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 03 + +Delete the Trunks and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependency diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/00-assert.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/00-assert.yaml new file mode 100644 index 000000000..f6904cc7b --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/00-assert.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Port/trunk-import-dependency to be ready + Waiting for Project/trunk-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Port/trunk-import-dependency to be ready + Waiting for Project/trunk-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/00-import-resource.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/00-import-resource.yaml new file mode 100644 index 000000000..4f8c0bc59 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/00-import-resource.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: trunk-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: trunk-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: trunk-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + portRef: trunk-import-dependency + projectRef: trunk-import-dependency diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/00-secret.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/01-assert.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/01-assert.yaml new file mode 100644 index 000000000..8190ecc75 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/01-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-dependency-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Port/trunk-import-dependency to be ready + Waiting for Project/trunk-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Port/trunk-import-dependency to be ready + Waiting for Project/trunk-import-dependency to be ready + status: "True" + reason: Progressing diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/01-create-trap-resource.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/01-create-trap-resource.yaml new file mode 100644 index 000000000..0289e6da8 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/01-create-trap-resource.yaml @@ -0,0 +1,65 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: trunk-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-import-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: trunk-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import-dependency + ipVersion: 4 + cidr: 192.168.156.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import-dependency + addresses: + - subnetRef: trunk-import-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: trunk-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# This `trunk-import-dependency-not-this-one` should not be picked by the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + portRef: trunk-import-dependency-not-this-one + projectRef: trunk-import-dependency-not-this-one diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/02-assert.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/02-assert.yaml new file mode 100644 index 000000000..a57266e42 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/02-assert.yaml @@ -0,0 +1,39 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-import-dependency + ref: trunk1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-import-dependency-not-this-one + ref: trunk2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-import-dependency + ref: port + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: trunk-import-dependency + ref: project +assertAll: + - celExpr: "trunk1.status.id != trunk2.status.id" + - celExpr: "trunk1.status.resource.portID == port.status.id" + - celExpr: "trunk1.status.resource.projectID == project.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-dependency +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/02-create-resource.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/02-create-resource.yaml new file mode 100644 index 000000000..549de2b13 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/02-create-resource.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import-dependency + addresses: + - subnetRef: trunk-import-dependency +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: trunk-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + portRef: trunk-import-dependency-external + projectRef: trunk-import-dependency-external diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/03-assert.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/03-assert.yaml new file mode 100644 index 000000000..a50d07a42 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/03-assert.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get port.openstack.k-orc.cloud trunk-import-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get project.openstack.k-orc.cloud trunk-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/03-delete-import-dependencies.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/03-delete-import-dependencies.yaml new file mode 100644 index 000000000..b818fa1a5 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/03-delete-import-dependencies.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We should be able to delete the import dependencies + - command: kubectl delete port.openstack.k-orc.cloud trunk-import-dependency + namespaced: true + - command: kubectl delete project.openstack.k-orc.cloud trunk-import-dependency + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/04-assert.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/04-assert.yaml new file mode 100644 index 000000000..059ed2ef6 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/04-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get trunk.openstack.k-orc.cloud trunk-import-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/04-delete-resource.yaml b/internal/controllers/trunk/tests/trunk-import-dependency/04-delete-resource.yaml new file mode 100644 index 000000000..10b0d3c75 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/04-delete-resource.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-import-dependency diff --git a/internal/controllers/trunk/tests/trunk-import-dependency/README.md b/internal/controllers/trunk/tests/trunk-import-dependency/README.md new file mode 100644 index 000000000..386f4830a --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-dependency/README.md @@ -0,0 +1,29 @@ +# Check dependency handling for imported Trunk + +## Step 00 + +Import a Trunk that references other imported resources. The referenced imported resources have no matching resources yet. +Verify the Trunk is waiting for the dependency to be ready. + +## Step 01 + +Create a Trunk matching the import filter, except for referenced resources, and verify that it's not being imported. + +## Step 02 + +Create the referenced resources and a Trunk matching the import filters. + +Verify that the observed status on the imported Trunk corresponds to the spec of the created Trunk. + +## Step 03 + +Delete the referenced resources and check that ORC does not prevent deletion. The OpenStack resources still exist because they +were imported resources and we only deleted the ORC representation of it. + +## Step 04 + +Delete the Trunk and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-dependency diff --git a/internal/controllers/trunk/tests/trunk-import-error/00-assert.yaml b/internal/controllers/trunk/tests/trunk-import-error/00-assert.yaml new file mode 100644 index 000000000..6e538ab91 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-error/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-error-external-1 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-error-external-2 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/trunk/tests/trunk-import-error/00-create-resources.yaml b/internal/controllers/trunk/tests/trunk-import-error/00-create-resources.yaml new file mode 100644 index 000000000..03f2ccd34 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-error/00-create-resources.yaml @@ -0,0 +1,80 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: trunk-import-error +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-import-error +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: trunk-import-error +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import-error + ipVersion: 4 + cidr: 192.168.156.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-import-error-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import-error + addresses: + - subnetRef: trunk-import-error +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-import-error-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import-error + addresses: + - subnetRef: trunk-import-error +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-error-external-1 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Trunk from "import error" test + portRef: trunk-import-error-1 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-error-external-2 +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Trunk from "import error" test + portRef: trunk-import-error-2 diff --git a/internal/controllers/trunk/tests/trunk-import-error/00-secret.yaml b/internal/controllers/trunk/tests/trunk-import-error/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-error/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-import-error/01-assert.yaml b/internal/controllers/trunk/tests/trunk-import-error/01-assert.yaml new file mode 100644 index 000000000..1f48b6bb9 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/trunk/tests/trunk-import-error/01-import-resource.yaml b/internal/controllers/trunk/tests/trunk-import-error/01-import-resource.yaml new file mode 100644 index 000000000..d3d922853 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-error/01-import-resource.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-error +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + description: Trunk from "import error" test diff --git a/internal/controllers/trunk/tests/trunk-import-error/README.md b/internal/controllers/trunk/tests/trunk-import-error/README.md new file mode 100644 index 000000000..ce3ec498f --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import-error/README.md @@ -0,0 +1,13 @@ +# Import Trunk with more than one matching resources + +## Step 00 + +Create two Trunks with identical specs. + +## Step 01 + +Ensure that an imported Trunk with a filter matching the resources returns an error. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error diff --git a/internal/controllers/trunk/tests/trunk-import/00-assert.yaml b/internal/controllers/trunk/tests/trunk-import/00-assert.yaml new file mode 100644 index 000000000..4ee876cb5 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/00-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/trunk/tests/trunk-import/00-import-resource.yaml b/internal/controllers/trunk/tests/trunk-import/00-import-resource.yaml new file mode 100644 index 000000000..9bb9fa452 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/00-import-resource.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: trunk-import-external + description: Trunk trunk-import-external from "trunk-import" test + adminStateUp: true + tags: + - trunk-import-tag diff --git a/internal/controllers/trunk/tests/trunk-import/00-secret.yaml b/internal/controllers/trunk/tests/trunk-import/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-import/01-assert.yaml b/internal/controllers/trunk/tests/trunk-import/01-assert.yaml new file mode 100644 index 000000000..7ae99dc6b --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/01-assert.yaml @@ -0,0 +1,36 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-external-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: trunk-import-external-not-this-one + description: Trunk trunk-import-external from "trunk-import" test + adminStateUp: true + tags: + - trunk-import-tag +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/trunk/tests/trunk-import/01-create-trap-resource.yaml b/internal/controllers/trunk/tests/trunk-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..df57a1f5f --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/01-create-trap-resource.yaml @@ -0,0 +1,59 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: trunk-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-import +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: trunk-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import + ipVersion: 4 + cidr: 192.168.156.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import + addresses: + - subnetRef: trunk-import +--- +# This `trunk-import-external-not-this-one` resource serves two purposes: +# - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) +# - ensure that importing a resource which name is a substring of it will not pick this one. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Trunk trunk-import-external from "trunk-import" test + portRef: trunk-import-external-not-this-one + adminStateUp: true + tags: + - trunk-import-tag diff --git a/internal/controllers/trunk/tests/trunk-import/02-assert.yaml b/internal/controllers/trunk/tests/trunk-import/02-assert.yaml new file mode 100644 index 000000000..b56a2d745 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/02-assert.yaml @@ -0,0 +1,35 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-import-external + ref: trunk1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-import-external-not-this-one + ref: trunk2 +assertAll: + - celExpr: "trunk1.status.id != trunk2.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: trunk-import-external + description: Trunk trunk-import-external from "trunk-import" test + adminStateUp: true + tags: + - trunk-import-tag diff --git a/internal/controllers/trunk/tests/trunk-import/02-create-resource.yaml b/internal/controllers/trunk/tests/trunk-import/02-create-resource.yaml new file mode 100644 index 000000000..7ce4ff50e --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/02-create-resource.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-import + addresses: + - subnetRef: trunk-import +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-import-external +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Trunk trunk-import-external from "trunk-import" test + portRef: trunk-import + adminStateUp: true + tags: + - trunk-import-tag diff --git a/internal/controllers/trunk/tests/trunk-import/README.md b/internal/controllers/trunk/tests/trunk-import/README.md new file mode 100644 index 000000000..a0d99d2ce --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-import/README.md @@ -0,0 +1,18 @@ +# Import Trunk + +## Step 00 + +Import a trunk that matches all fields in the filter, and verify it is waiting for the external resource to be created. + +## Step 01 + +Create a trunk whose name is a superstring of the one specified in the import filter, otherwise matching the filter, and verify that it's not being imported. + +## Step 02 + +Create a trunk matching the filter and verify that the observed status on the imported trunk corresponds to the spec of the created trunk. +Also, confirm that it does not adopt any trunk whose name is a superstring of its own. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import diff --git a/internal/controllers/trunk/tests/trunk-update/00-assert.yaml b/internal/controllers/trunk/tests/trunk-update/00-assert.yaml new file mode 100644 index 000000000..b6701deb0 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/00-assert.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +status: + resource: + name: trunk-update + adminStateUp: true + status: ACTIVE + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-update + ref: trunk + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-update + ref: port +assertAll: + - celExpr: "trunk.status.id != ''" + - celExpr: "trunk.status.resource.portID == port.status.id" + - celExpr: "trunk.status.resource.projectID != ''" + - celExpr: "trunk.status.resource.tenantID != ''" + - celExpr: "trunk.status.resource.createdAt != ''" + - celExpr: "trunk.status.resource.updatedAt != ''" + - celExpr: "trunk.status.resource.revisionNumber > 0" + - celExpr: "!has(trunk.status.resource.description)" + - celExpr: "!has(trunk.status.resource.tags)" + - celExpr: "!has(trunk.status.resource.subports)" diff --git a/internal/controllers/trunk/tests/trunk-update/00-minimal-resource.yaml b/internal/controllers/trunk/tests/trunk-update/00-minimal-resource.yaml new file mode 100644 index 000000000..150368865 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/00-minimal-resource.yaml @@ -0,0 +1,52 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: trunk-update +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: trunk-update +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Subnet +metadata: + name: trunk-update +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-update + ipVersion: 4 + cidr: 192.168.156.0/24 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-update +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-update + addresses: + - subnetRef: trunk-update +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + portRef: trunk-update diff --git a/internal/controllers/trunk/tests/trunk-update/00-prerequisites.yaml b/internal/controllers/trunk/tests/trunk-update/00-prerequisites.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/00-prerequisites.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-update/01-assert.yaml b/internal/controllers/trunk/tests/trunk-update/01-assert.yaml new file mode 100644 index 000000000..3d5aaaffc --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/01-assert.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +status: + resource: + name: trunk-update-updated + description: trunk-update-updated + adminStateUp: true + status: ACTIVE + tags: + - tag1 + - tag2 + subports: + - segmentationID: 100 + segmentationType: vlan + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-update + ref: trunk + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-update + ref: port + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-update-subport + ref: subport +assertAll: + - celExpr: "trunk.status.id != ''" + - celExpr: "trunk.status.resource.portID == port.status.id" + - celExpr: "trunk.status.resource.projectID != ''" + - celExpr: "trunk.status.resource.tenantID != ''" + - celExpr: "trunk.status.resource.createdAt != ''" + - celExpr: "trunk.status.resource.updatedAt != ''" + - celExpr: "trunk.status.resource.revisionNumber > 0" + - celExpr: "trunk.status.resource.subports.size() == 1" + - celExpr: "trunk.status.resource.subports[0].portID == subport.status.id" diff --git a/internal/controllers/trunk/tests/trunk-update/01-updated-resource.yaml b/internal/controllers/trunk/tests/trunk-update/01-updated-resource.yaml new file mode 100644 index 000000000..1968abbc4 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/01-updated-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Port +metadata: + name: trunk-update-subport +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + networkRef: trunk-update +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +spec: + resource: + name: trunk-update-updated + description: trunk-update-updated + subports: + - portRef: trunk-update-subport + segmentationID: 100 + segmentationType: vlan + tags: + - tag1 + - tag2 diff --git a/internal/controllers/trunk/tests/trunk-update/02-assert.yaml b/internal/controllers/trunk/tests/trunk-update/02-assert.yaml new file mode 100644 index 000000000..a29e0774d --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/02-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +status: + resource: + adminStateUp: false + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/trunk/tests/trunk-update/02-disable-trunk.yaml b/internal/controllers/trunk/tests/trunk-update/02-disable-trunk.yaml new file mode 100644 index 000000000..651030891 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/02-disable-trunk.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +spec: + resource: + adminStateUp: false diff --git a/internal/controllers/trunk/tests/trunk-update/03-assert.yaml b/internal/controllers/trunk/tests/trunk-update/03-assert.yaml new file mode 100644 index 000000000..9339079bc --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/03-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +status: + resource: + adminStateUp: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/trunk/tests/trunk-update/03-enable-trunk.yaml b/internal/controllers/trunk/tests/trunk-update/03-enable-trunk.yaml new file mode 100644 index 000000000..cc43865cf --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/03-enable-trunk.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +spec: + resource: + adminStateUp: true diff --git a/internal/controllers/trunk/tests/trunk-update/04-assert.yaml b/internal/controllers/trunk/tests/trunk-update/04-assert.yaml new file mode 100644 index 000000000..b6701deb0 --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/04-assert.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Trunk +metadata: + name: trunk-update +status: + resource: + name: trunk-update + adminStateUp: true + status: ACTIVE + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Trunk + name: trunk-update + ref: trunk + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Port + name: trunk-update + ref: port +assertAll: + - celExpr: "trunk.status.id != ''" + - celExpr: "trunk.status.resource.portID == port.status.id" + - celExpr: "trunk.status.resource.projectID != ''" + - celExpr: "trunk.status.resource.tenantID != ''" + - celExpr: "trunk.status.resource.createdAt != ''" + - celExpr: "trunk.status.resource.updatedAt != ''" + - celExpr: "trunk.status.resource.revisionNumber > 0" + - celExpr: "!has(trunk.status.resource.description)" + - celExpr: "!has(trunk.status.resource.tags)" + - celExpr: "!has(trunk.status.resource.subports)" diff --git a/internal/controllers/trunk/tests/trunk-update/04-reverted-resource.yaml b/internal/controllers/trunk/tests/trunk-update/04-reverted-resource.yaml new file mode 100644 index 000000000..2c6c253ff --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/04-reverted-resource.yaml @@ -0,0 +1,7 @@ +# NOTE: kuttl only does patch updates, which means we can't delete a field. +# We have to use a kubectl apply command instead. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl replace -f 00-minimal-resource.yaml + namespaced: true diff --git a/internal/controllers/trunk/tests/trunk-update/README.md b/internal/controllers/trunk/tests/trunk-update/README.md new file mode 100644 index 000000000..1f6cf231a --- /dev/null +++ b/internal/controllers/trunk/tests/trunk-update/README.md @@ -0,0 +1,25 @@ +# Update Trunk + +## Step 00 + +Create a Trunk using only mandatory fields. + +## Step 01 + +Update all mutable fields, except for `AdminStateUp`, since neutron disallow operations on disabled trunks. + +## Step 02 + +Update `AdminStateUp`. + +## Step 03 + +Re-enable the trunk by setting `AdminStateUp` to `true`. This must be done before reverting the resource, since neutron disallows operations on disabled trunks. + +## Step 04 + +Revert the resource to its original value and verify that the resulting object matches its state when first created. + +## Reference + +https://k-orc.cloud/development/writing-tests/#update diff --git a/internal/controllers/trunk/zz_generated.adapter.go b/internal/controllers/trunk/zz_generated.adapter.go new file mode 100644 index 000000000..274c087bf --- /dev/null +++ b/internal/controllers/trunk/zz_generated.adapter.go @@ -0,0 +1,98 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trunk + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.Trunk + orcObjectListT = orcv1alpha1.TrunkList + resourceSpecT = orcv1alpha1.TrunkResourceSpec + filterT = orcv1alpha1.TrunkFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = trunkAdapter +) + +type trunkAdapter struct { + *orcv1alpha1.Trunk +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.Trunk +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return f.Status.ID +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.ID +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} + +// getResourceName returns the name of the OpenStack resource we should use. +// This method is not implemented as part of APIObjectAdapter as it is intended +// to be used by resource actuators, which don't use the adapter. +func getResourceName(orcObject orcObjectPT) string { + if orcObject.Spec.Resource.Name != nil { + return string(*orcObject.Spec.Resource.Name) + } + return orcObject.Name +} diff --git a/internal/controllers/trunk/zz_generated.controller.go b/internal/controllers/trunk/zz_generated.controller.go new file mode 100644 index 000000000..6b36c15cc --- /dev/null +++ b/internal/controllers/trunk/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trunk + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/controllers/user/actuator.go b/internal/controllers/user/actuator.go new file mode 100644 index 000000000..552eea60c --- /dev/null +++ b/internal/controllers/user/actuator.go @@ -0,0 +1,388 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package user + +import ( + "context" + "iter" + + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/users" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/applyconfigs" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +// OpenStack resource types +type ( + osResourceT = users.User + + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + resourceReconciler = interfaces.ResourceReconciler[orcObjectPT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) + +type userActuator struct { + osClient osclients.UserClient + k8sClient client.Client +} + +var _ createResourceActuator = userActuator{} +var _ deleteResourceActuator = userActuator{} + +func (userActuator) GetResourceID(osResource *osResourceT) string { + return osResource.ID +} + +func (actuator userActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) { + resource, err := actuator.osClient.GetUser(ctx, id) + if err != nil { + return nil, progress.WrapError(err) + } + return resource, nil +} + +func (actuator userActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + // Resolve the domain ID from DomainRef if set. Without the domain + // ID, adoption could match a user in the wrong domain. + var domainID string + if resourceSpec.DomainRef != nil { + domain, rs := dependency.FetchDependency( + ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.DomainRef, "Domain", + func(dep *orcv1alpha1.Domain) bool { + return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil + }, + ) + if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule { + return nil, false + } + domainID = ptr.Deref(domain.Status.ID, "") + } + + listOpts := users.ListOpts{ + Name: getResourceName(orcObject), + DomainID: domainID, + } + + return actuator.osClient.ListUsers(ctx, listOpts), true +} + +func (actuator userActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + var reconcileStatus progress.ReconcileStatus + + domain, rs := dependency.FetchDependency[*orcv1alpha1.Domain]( + ctx, actuator.k8sClient, obj.Namespace, + filter.DomainRef, "Domain", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + listOpts := users.ListOpts{ + Name: string(ptr.Deref(filter.Name, "")), + DomainID: ptr.Deref(domain.Status.ID, ""), + } + + return actuator.osClient.ListUsers(ctx, listOpts), reconcileStatus +} + +func (actuator userActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + var reconcileStatus progress.ReconcileStatus + + var domainID string + if resource.DomainRef != nil { + domain, domainDepRS := domainDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(domainDepRS) + if domain != nil { + domainID = ptr.Deref(domain.Status.ID, "") + } + } + + var defaultProjectID string + if resource.DefaultProjectRef != nil { + project, projectDepRS := projectDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS) + if project != nil { + defaultProjectID = ptr.Deref(project.Status.ID, "") + } + } + + var password string + if resource.PasswordRef != nil { + secret, secretReconcileStatus := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, + resource.PasswordRef, "Secret", + func(*corev1.Secret) bool { return true }, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(secretReconcileStatus) + if secretReconcileStatus == nil { + passwordBytes, ok := secret.Data["password"] + if !ok { + reconcileStatus = reconcileStatus.WithReconcileStatus( + progress.NewReconcileStatus().WithProgressMessage("Password secret does not contain \"password\" key")) + } else { + password = string(passwordBytes) + } + } + } + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + createOpts := users.CreateOpts{ + Name: getResourceName(obj), + Description: ptr.Deref(resource.Description, ""), + DomainID: domainID, + Enabled: resource.Enabled, + DefaultProjectID: defaultProjectID, + Password: password, + } + + osResource, err := actuator.osClient.CreateUser(ctx, createOpts) + if err != nil { + // We should require the spec to be updated before retrying a create which returned a conflict + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + return osResource, nil +} + +func (actuator userActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + return progress.WrapError(actuator.osClient.DeleteUser(ctx, resource.ID)) +} + +func (actuator userActuator) reconcilePassword(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil || resource.PasswordRef == nil { + return nil + } + + currentRef := string(*resource.PasswordRef) + var lastAppliedRef string + if obj.Status.Resource != nil { + lastAppliedRef = obj.Status.Resource.AppliedPasswordRef + } + + if lastAppliedRef == currentRef { + return nil + } + + // Read the password from the referenced Secret + secret, secretRS := dependency.FetchDependency( + ctx, actuator.k8sClient, obj.Namespace, + resource.PasswordRef, "Secret", + func(*corev1.Secret) bool { return true }, + ) + if secretRS != nil { + return secretRS + } + + passwordBytes, ok := secret.Data["password"] + if !ok { + return progress.NewReconcileStatus().WithProgressMessage("Password secret does not contain \"password\" key") + } + password := string(passwordBytes) + + // Only call UpdateUser if this is not the first reconcile after creation. + // CreateResource already set the initial password. + if lastAppliedRef != "" { + log.V(logging.Info).Info("Updating password") + _, err := actuator.osClient.UpdateUser(ctx, osResource.ID, users.UpdateOpts{ + Password: password, + }) + + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) + } + } + + // Update the lastAppliedPasswordRef status field via a MergePatch. + // MergePatch sets only the specified fields without claiming SSA + // ownership, so the main SSA status update won't remove this field. + statusApply := orcapplyconfigv1alpha1.UserResourceStatus(). + WithAppliedPasswordRef(currentRef) + applyConfig := orcapplyconfigv1alpha1.User(obj.Name, obj.Namespace). + WithUID(obj.UID). + WithStatus(orcapplyconfigv1alpha1.UserStatus(). + WithResource(statusApply)) + if err := actuator.k8sClient.Status().Patch(ctx, obj, + applyconfigs.Patch(types.MergePatchType, applyConfig)); err != nil { + return progress.WrapError(err) + } + + if lastAppliedRef != "" { + return progress.NeedsRefresh() + } + return nil +} + +func (actuator userActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + // Should have been caught by API validation + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + + updateOpts := users.UpdateOpts{} + + handleNameUpdate(&updateOpts, obj, osResource) + handleDescriptionUpdate(&updateOpts, resource, osResource) + handleEnabledUpdate(&updateOpts, resource, osResource) + + needsUpdate, err := needsUpdate(updateOpts) + if err != nil { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err)) + } + if !needsUpdate { + log.V(logging.Debug).Info("No changes") + return nil + } + + _, err = actuator.osClient.UpdateUser(ctx, osResource.ID, updateOpts) + + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) + } + + return progress.NeedsRefresh() +} + +func needsUpdate(updateOpts users.UpdateOpts) (bool, error) { + updateOptsMap, err := updateOpts.ToUserUpdateMap() + if err != nil { + return false, err + } + + updateMap, ok := updateOptsMap["user"].(map[string]any) + if !ok { + updateMap = make(map[string]any) + } + + return len(updateMap) > 0, nil +} + +func handleNameUpdate(updateOpts *users.UpdateOpts, obj orcObjectPT, osResource *osResourceT) { + name := getResourceName(obj) + if osResource.Name != name { + updateOpts.Name = name + } +} + +func handleDescriptionUpdate(updateOpts *users.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + description := ptr.Deref(resource.Description, "") + if osResource.Description != description { + updateOpts.Description = &description + } +} + +func handleEnabledUpdate(updateOpts *users.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + enabled := ptr.Deref(resource.Enabled, true) + if osResource.Enabled != enabled { + updateOpts.Enabled = &enabled + } +} + +func (actuator userActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.reconcilePassword, + actuator.updateResource, + }, nil +} + +type userHelperFactory struct{} + +var _ helperFactory = userHelperFactory{} + +func newActuator(ctx context.Context, orcObject *orcv1alpha1.User, controller interfaces.ResourceController) (userActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, controller.GetK8sClient(), orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return userActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject) + if err != nil { + return userActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewUserClient() + if err != nil { + return userActuator{}, progress.WrapError(err) + } + + return userActuator{ + osClient: osClient, + k8sClient: controller.GetK8sClient(), + }, nil +} + +func (userHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { + return userAdapter{obj} +} + +func (userHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} + +func (userHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} diff --git a/internal/controllers/user/actuator_test.go b/internal/controllers/user/actuator_test.go new file mode 100644 index 000000000..aefc193da --- /dev/null +++ b/internal/controllers/user/actuator_test.go @@ -0,0 +1,321 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package user + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/users" + "go.uber.org/mock/gomock" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients/mock" +) + +func TestNeedsUpdate(t *testing.T) { + testCases := []struct { + name string + updateOpts users.UpdateOpts + expectChange bool + }{ + { + name: "Empty base opts", + updateOpts: users.UpdateOpts{}, + expectChange: false, + }, + { + name: "Updated opts", + updateOpts: users.UpdateOpts{Name: "updated"}, + expectChange: true, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + got, _ := needsUpdate(tt.updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestHandleNameUpdate(t *testing.T) { + ptrToName := ptr.To[orcv1alpha1.OpenStackName] + testCases := []struct { + name string + newValue *orcv1alpha1.OpenStackName + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToName("name"), existingValue: "name", expectChange: false}, + {name: "Different", newValue: ptrToName("new-name"), existingValue: "name", expectChange: true}, + {name: "No value provided, existing is identical to object name", newValue: nil, existingValue: "object-name", expectChange: false}, + {name: "No value provided, existing is different from object name", newValue: nil, existingValue: "different-from-object-name", expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.User{} + resource.Name = "object-name" + resource.Spec = orcv1alpha1.UserSpec{ + Resource: &orcv1alpha1.UserResourceSpec{Name: tt.newValue}, + } + osResource := &osResourceT{Name: tt.existingValue} + + updateOpts := users.UpdateOpts{} + handleNameUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleDescriptionUpdate(t *testing.T) { + ptrToDescription := ptr.To[string] + testCases := []struct { + name string + newValue *string + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToDescription("desc"), existingValue: "desc", expectChange: false}, + {name: "Different", newValue: ptrToDescription("new-desc"), existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is set", newValue: nil, existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is empty", newValue: nil, existingValue: "", expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.UserResourceSpec{Description: tt.newValue} + osResource := &osResourceT{Description: tt.existingValue} + + updateOpts := users.UpdateOpts{} + handleDescriptionUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleEnabledUpdate(t *testing.T) { + ptrToBool := ptr.To[bool] + testCases := []struct { + name string + newValue *bool + existingValue bool + expectChange bool + }{ + {name: "Identical", newValue: ptrToBool(true), existingValue: true, expectChange: false}, + {name: "Different", newValue: ptrToBool(true), existingValue: false, expectChange: true}, + {name: "No value provided, existing is set", newValue: nil, existingValue: false, expectChange: true}, + {name: "No value provided, existing is default", newValue: nil, existingValue: true, expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.UserResourceSpec{Enabled: tt.newValue} + osResource := &users.User{Enabled: tt.existingValue} + + updateOpts := users.UpdateOpts{} + handleEnabledUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestReconcilePassword(t *testing.T) { + ptrToPasswordRef := ptr.To[orcv1alpha1.KubernetesNameRef] + testCases := []struct { + name string + orcObject *orcv1alpha1.User + osResource *users.User + secret *corev1.Secret + setupMock func(*mock.MockUserClientMockRecorder) + wantReschedule bool + wantErr bool + }{ + { + name: "No password ref set", + orcObject: &orcv1alpha1.User{ + Spec: orcv1alpha1.UserSpec{ + Resource: &orcv1alpha1.UserResourceSpec{}, + }, + }, + osResource: &users.User{ID: "user-id"}, + wantReschedule: false, + wantErr: false, + }, + { + name: "Resource is nil", + orcObject: &orcv1alpha1.User{ + Spec: orcv1alpha1.UserSpec{}, + }, + osResource: &users.User{ID: "user-id"}, + wantReschedule: false, + wantErr: false, + }, + { + name: "Password ref unchanged", + orcObject: &orcv1alpha1.User{ + Spec: orcv1alpha1.UserSpec{ + Resource: &orcv1alpha1.UserResourceSpec{ + PasswordRef: ptrToPasswordRef("my-secret"), + }, + }, + Status: orcv1alpha1.UserStatus{ + Resource: &orcv1alpha1.UserResourceStatus{ + AppliedPasswordRef: "my-secret", + }, + }, + }, + osResource: &users.User{ID: "user-id"}, + wantReschedule: false, + wantErr: false, + }, + { + name: "First password set - no UpdateUser call", + orcObject: &orcv1alpha1.User{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-user", + Namespace: "test-ns", + UID: "test-uid", + }, + Spec: orcv1alpha1.UserSpec{ + Resource: &orcv1alpha1.UserResourceSpec{ + PasswordRef: ptrToPasswordRef("my-secret"), + }, + }, + Status: orcv1alpha1.UserStatus{ + Resource: &orcv1alpha1.UserResourceStatus{ + AppliedPasswordRef: "", + }, + }, + }, + osResource: &users.User{ID: "user-id"}, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-secret", + Namespace: "test-ns", + }, + Data: map[string][]byte{ + "password": []byte("mypassword123"), + }, + }, + // No UpdateUser call expected on first reconcile + setupMock: func(recorder *mock.MockUserClientMockRecorder) {}, + wantReschedule: false, + wantErr: false, + }, + { + name: "Password changed - UpdateUser called", + orcObject: &orcv1alpha1.User{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-user", + Namespace: "test-ns", + UID: "test-uid", + }, + Spec: orcv1alpha1.UserSpec{ + Resource: &orcv1alpha1.UserResourceSpec{ + PasswordRef: ptrToPasswordRef("my-secret"), + }, + }, + Status: orcv1alpha1.UserStatus{ + Resource: &orcv1alpha1.UserResourceStatus{ + AppliedPasswordRef: "old-secret", + }, + }, + }, + osResource: &users.User{ID: "user-id"}, + secret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-secret", + Namespace: "test-ns", + }, + Data: map[string][]byte{ + "password": []byte("newpassword456"), + }, + }, + setupMock: func(recorder *mock.MockUserClientMockRecorder) { + recorder.UpdateUser(gomock.Any(), "user-id", gomock.Any()).Return(&users.User{}, nil) + }, + wantReschedule: true, // NeedsRefresh returns true + wantErr: false, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + mockctrl := gomock.NewController(t) + userClient := mock.NewMockUserClient(mockctrl) + + // Create fake k8s client + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = orcv1alpha1.AddToScheme(scheme) + + objects := []client.Object{tt.orcObject} + if tt.secret != nil { + objects = append(objects, tt.secret) + } + + k8sClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(objects...). + WithStatusSubresource(&orcv1alpha1.User{}). + Build() + + actuator := userActuator{ + osClient: userClient, + k8sClient: k8sClient, + } + + if tt.setupMock != nil { + tt.setupMock(userClient.EXPECT()) + } + + reconcileStatus := actuator.reconcilePassword(context.TODO(), tt.orcObject, tt.osResource) + + needsReschedule, err := reconcileStatus.NeedsReschedule() + if (err != nil) != tt.wantErr { + t.Errorf("reconcilePassword() error = %v, wantErr %v", err, tt.wantErr) + } + if needsReschedule != tt.wantReschedule { + t.Errorf("reconcilePassword() needsReschedule = %v, want %v", needsReschedule, tt.wantReschedule) + } + }) + } +} diff --git a/internal/controllers/user/controller.go b/internal/controllers/user/controller.go new file mode 100644 index 000000000..86e34b4b1 --- /dev/null +++ b/internal/controllers/user/controller.go @@ -0,0 +1,167 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package user + +import ( + "context" + "errors" + "time" + + corev1 "k8s.io/api/core/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "user" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=users,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=users/status,verbs=get;update;patch + +type userReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return &userReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (userReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *userReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var domainDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.UserList, *orcv1alpha1.Domain]( + "spec.resource.domainRef", + func(user *orcv1alpha1.User) []string { + resource := user.Spec.Resource + if resource == nil || resource.DomainRef == nil { + return nil + } + return []string{string(*resource.DomainRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var projectDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.UserList, *orcv1alpha1.Project]( + "spec.resource.defaultProjectRef", + func(user *orcv1alpha1.User) []string { + resource := user.Spec.Resource + if resource == nil || resource.DefaultProjectRef == nil { + return nil + } + return []string{string(*resource.DefaultProjectRef)} + }, + finalizer, externalObjectFieldOwner, +) + +var domainImportDependency = dependency.NewDependency[*orcv1alpha1.UserList, *orcv1alpha1.Domain]( + "spec.import.filter.domainRef", + func(user *orcv1alpha1.User) []string { + resource := user.Spec.Import + if resource == nil || resource.Filter == nil || resource.Filter.DomainRef == nil { + return nil + } + return []string{string(*resource.Filter.DomainRef)} + }, +) + +var passwordDependency = dependency.NewDependency[*orcv1alpha1.UserList, *corev1.Secret]( + "spec.resource.passwordRef", + func(user *orcv1alpha1.User) []string { + resource := user.Spec.Resource + if resource == nil || resource.PasswordRef == nil { + return nil + } + return []string{string(*resource.PasswordRef)} + }, +) + +// SetupWithManager sets up the controller with the Manager. +func (c *userReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + domainWatchEventHandler, err := domainDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + projectWatchEventHandler, err := projectDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + domainImportWatchEventHandler, err := domainImportDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + passwordWatchEventHandler, err := passwordDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&orcv1alpha1.User{}). + Watches(&orcv1alpha1.Domain{}, domainWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Domain{})), + ). + Watches(&orcv1alpha1.Project{}, projectWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})), + ). + // A second watch is necessary because we need a different handler that omits deletion guards + Watches(&orcv1alpha1.Domain{}, domainImportWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Domain{})), + ). + // XXX: This is a general watch on secrets. A general watch on secrets + // is undesirable because: + // - It requires problematic RBAC + // - Secrets are arbitrarily large, and we don't want to cache their contents + // + // These will require separate solutions. For the latter we should + // probably use a MetadataOnly watch on secrets. + Watches(&corev1.Secret{}, passwordWatchEventHandler) + + if err := errors.Join( + domainDependency.AddToManager(ctx, mgr), + projectDependency.AddToManager(ctx, mgr), + domainImportDependency.AddToManager(ctx, mgr), + passwordDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, userHelperFactory{}, userStatusWriter{}, c.defaultResyncPeriod) + return builder.Complete(&r) +} diff --git a/internal/controllers/user/status.go b/internal/controllers/user/status.go new file mode 100644 index 000000000..e412d66fd --- /dev/null +++ b/internal/controllers/user/status.go @@ -0,0 +1,72 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package user + +import ( + "time" + + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type userStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.UserApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.UserStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.User, *osResourceT, *objectApplyT, *statusApplyT] = userStatusWriter{} + +func (userStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.User(name, namespace) +} + +func (userStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.User, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource == nil { + if orcObject.Status.ID == nil { + return metav1.ConditionFalse, nil + } else { + return metav1.ConditionUnknown, nil + } + } + return metav1.ConditionTrue, nil +} + +func (userStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.UserResourceStatus(). + WithDomainID(osResource.DomainID). + WithName(osResource.Name). + WithEnabled(osResource.Enabled) + + if osResource.Description != "" { + resourceStatus.WithDescription(osResource.Description) + } + + if osResource.DefaultProjectID != "" { + resourceStatus.WithDefaultProjectID(osResource.DefaultProjectID) + } + + if !osResource.PasswordExpiresAt.IsZero() { + resourceStatus.WithPasswordExpiresAt(osResource.PasswordExpiresAt.Format(time.RFC3339)) + } + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/user/tests/user-create-full/00-assert.yaml b/internal/controllers/user/tests/user-create-full/00-assert.yaml new file mode 100644 index 000000000..b91d5b2dd --- /dev/null +++ b/internal/controllers/user/tests/user-create-full/00-assert.yaml @@ -0,0 +1,39 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-create-full +status: + resource: + name: user-create-full-override + description: User from "create full" test + enabled: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-create-full + ref: user + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-create-full + ref: domain + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: user-create-full + ref: project +assertAll: + - celExpr: "user.status.id != ''" + - celExpr: "user.status.resource.domainID == domain.status.id" + - celExpr: "user.status.resource.defaultProjectID == project.status.id" + # passwordExpiresAt depends on the Keystone security_compliance + # configuration and is not asserted here. diff --git a/internal/controllers/user/tests/user-create-full/00-create-resource.yaml b/internal/controllers/user/tests/user-create-full/00-create-resource.yaml new file mode 100644 index 000000000..53d6869bb --- /dev/null +++ b/internal/controllers/user/tests/user-create-full/00-create-resource.yaml @@ -0,0 +1,47 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: user-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: v1 +kind: Secret +metadata: + name: user-create-full +type: Opaque +stringData: + password: "TestPassword" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-create-full +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + name: user-create-full-override + description: User from "create full" test + domainRef: user-create-full + defaultProjectRef: user-create-full + enabled: true + passwordRef: user-create-full diff --git a/internal/controllers/user/tests/user-create-full/00-secret.yaml b/internal/controllers/user/tests/user-create-full/00-secret.yaml new file mode 100644 index 000000000..082860af5 --- /dev/null +++ b/internal/controllers/user/tests/user-create-full/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-create-full/01-assert.yaml b/internal/controllers/user/tests/user-create-full/01-assert.yaml new file mode 100644 index 000000000..5ec861ec8 --- /dev/null +++ b/internal/controllers/user/tests/user-create-full/01-assert.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-create-full + ref: domain +assertAll: + - celExpr: "domain.status.resource.enabled == false" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-create-full/01-disable-domain.yaml b/internal/controllers/user/tests/user-create-full/01-disable-domain.yaml new file mode 100644 index 000000000..c47f2b2a5 --- /dev/null +++ b/internal/controllers/user/tests/user-create-full/01-disable-domain.yaml @@ -0,0 +1,7 @@ +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-create-full +spec: + resource: + enabled: false \ No newline at end of file diff --git a/internal/controllers/user/tests/user-create-full/README.md b/internal/controllers/user/tests/user-create-full/README.md new file mode 100644 index 000000000..fd9b95197 --- /dev/null +++ b/internal/controllers/user/tests/user-create-full/README.md @@ -0,0 +1,11 @@ +# Create a User with all the options + +## Step 00 + +Create a User using all available fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name from the spec when it is specified. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/user/tests/user-create-minimal/00-assert.yaml b/internal/controllers/user/tests/user-create-minimal/00-assert.yaml new file mode 100644 index 000000000..f8ffcb148 --- /dev/null +++ b/internal/controllers/user/tests/user-create-minimal/00-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-create-minimal +status: + resource: + name: user-create-minimal + enabled: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-create-minimal + ref: user +assertAll: + - celExpr: "user.status.id != ''" + - celExpr: "!has(user.status.resource.description)" + - celExpr: "user.status.resource.domainID == 'default'" + - celExpr: "!has(user.status.resource.defaultProjectID)" + # passwordExpiresAt depends on the Keystone security_compliance + # configuration and is not asserted here. + diff --git a/internal/controllers/user/tests/user-create-minimal/00-create-resource.yaml b/internal/controllers/user/tests/user-create-minimal/00-create-resource.yaml new file mode 100644 index 000000000..c3d2147bf --- /dev/null +++ b/internal/controllers/user/tests/user-create-minimal/00-create-resource.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-create-minimal +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} \ No newline at end of file diff --git a/internal/controllers/user/tests/user-create-minimal/00-secret.yaml b/internal/controllers/user/tests/user-create-minimal/00-secret.yaml new file mode 100644 index 000000000..082860af5 --- /dev/null +++ b/internal/controllers/user/tests/user-create-minimal/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-create-minimal/01-assert.yaml b/internal/controllers/user/tests/user-create-minimal/01-assert.yaml new file mode 100644 index 000000000..df50748c8 --- /dev/null +++ b/internal/controllers/user/tests/user-create-minimal/01-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: v1 + kind: Secret + name: openstack-clouds + ref: secret +assertAll: + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/user' in secret.metadata.finalizers" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-create-minimal/01-delete-secret.yaml b/internal/controllers/user/tests/user-create-minimal/01-delete-secret.yaml new file mode 100644 index 000000000..c3e557604 --- /dev/null +++ b/internal/controllers/user/tests/user-create-minimal/01-delete-secret.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete secret openstack-clouds --wait=false + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-create-minimal/README.md b/internal/controllers/user/tests/user-create-minimal/README.md new file mode 100644 index 000000000..548da3f08 --- /dev/null +++ b/internal/controllers/user/tests/user-create-minimal/README.md @@ -0,0 +1,15 @@ +# Create a User with the minimum options + +## Step 00 + +Create a minimal User without a password, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified. + +## Step 01 + +Try deleting the secret and ensure that it is not deleted thanks to the finalizer. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/user/tests/user-dependency/00-assert.yaml b/internal/controllers/user/tests/user-dependency/00-assert.yaml new file mode 100644 index 000000000..f45da298d --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/00-assert.yaml @@ -0,0 +1,60 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-secret +status: + conditions: + - type: Available + message: Waiting for Secret/user-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/user-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-domain +status: + conditions: + - type: Available + message: Waiting for Domain/user-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Domain/user-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-project +status: + conditions: + - type: Available + message: Waiting for Project/user-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Project/user-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-password +status: + conditions: + - type: Available + message: Waiting for Secret/user-dependency-password to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/user-dependency-password to be created + status: "True" + reason: Progressing \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/user/tests/user-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..c06e90511 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-domain +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + domainRef: user-dependency + passwordRef: user-dependency-password-existing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-project +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + defaultProjectRef: user-dependency + passwordRef: user-dependency-password-existing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-secret +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: user-dependency + managementPolicy: managed + resource: + passwordRef: user-dependency-password-existing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-password +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + passwordRef: user-dependency-password \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/00-secret.yaml b/internal/controllers/user/tests/user-dependency/00-secret.yaml new file mode 100644 index 000000000..1e9d5d5fb --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/00-secret.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true +--- +apiVersion: v1 +kind: Secret +metadata: + name: user-dependency-password-existing +type: Opaque +stringData: + password: "TestPassword" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/01-assert.yaml b/internal/controllers/user/tests/user-dependency/01-assert.yaml new file mode 100644 index 000000000..83de36848 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/01-assert.yaml @@ -0,0 +1,60 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-secret +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-domain +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-project +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-dependency-no-password +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/01-create-dependencies.yaml b/internal/controllers/user/tests/user-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..2823b9d99 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/01-create-dependencies.yaml @@ -0,0 +1,36 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic user-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Project +metadata: + name: user-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: v1 +kind: Secret +metadata: + name: user-dependency-password +type: Opaque +stringData: + password: "TestPassword" diff --git a/internal/controllers/user/tests/user-dependency/02-assert.yaml b/internal/controllers/user/tests/user-dependency/02-assert.yaml new file mode 100644 index 000000000..a5a8dd7f7 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/02-assert.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-dependency + ref: domain +assertAll: + - celExpr: "domain.status.resource.enabled == false" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/02-disable-domain.yaml b/internal/controllers/user/tests/user-dependency/02-disable-domain.yaml new file mode 100644 index 000000000..494189845 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/02-disable-domain.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-dependency +spec: + resource: + enabled: false \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/03-assert.yaml b/internal/controllers/user/tests/user-dependency/03-assert.yaml new file mode 100644 index 000000000..7f6b3c162 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/03-assert.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-dependency + ref: domain + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Project + name: user-dependency + ref: project + - apiVersion: v1 + kind: Secret + name: user-dependency + ref: secret +assertAll: + - celExpr: "domain.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/user' in domain.metadata.finalizers" + - celExpr: "project.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/user' in project.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/user' in secret.metadata.finalizers" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/03-delete-dependencies.yaml b/internal/controllers/user/tests/user-dependency/03-delete-dependencies.yaml new file mode 100644 index 000000000..6e751521b --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/03-delete-dependencies.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete domain.openstack.k-orc.cloud user-dependency --wait=false + namespaced: true + - command: kubectl delete project.openstack.k-orc.cloud user-dependency --wait=false + namespaced: true + - command: kubectl delete secret user-dependency --wait=false + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/04-assert.yaml b/internal/controllers/user/tests/user-dependency/04-assert.yaml new file mode 100644 index 000000000..a33f164ef --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/04-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get domain.openstack.k-orc.cloud user-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get project.openstack.k-orc.cloud user-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret user-dependency --namespace $NAMESPACE" + skipLogOutput: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/04-delete-resources.yaml b/internal/controllers/user/tests/user-dependency/04-delete-resources.yaml new file mode 100644 index 000000000..e0787a012 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/04-delete-resources.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-dependency-no-domain +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-dependency-no-project +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-dependency-no-password \ No newline at end of file diff --git a/internal/controllers/user/tests/user-dependency/README.md b/internal/controllers/user/tests/user-dependency/README.md new file mode 100644 index 000000000..cda61e315 --- /dev/null +++ b/internal/controllers/user/tests/user-dependency/README.md @@ -0,0 +1,25 @@ +# Creation and deletion dependencies + +## Step 00 + +Create Users referencing non-existing resources. Each User is dependent on other non-existing resource. Verify that the Users are waiting for the needed resources to be created externally. + +## Step 01 + +Create the missing dependencies and verify all the Users are available. + +## Step 02 + +Disable the domain dependency to allow KUTTL to cleanup resources without any issues. + +## Step 03 + +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 04 + +Delete the Users and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependency \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/00-assert.yaml b/internal/controllers/user/tests/user-import-dependency/00-assert.yaml new file mode 100644 index 000000000..607b6d635 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/00-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Domain/user-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Domain/user-import-dependency to be ready + status: "True" + reason: Progressing \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/00-import-resource.yaml b/internal/controllers/user/tests/user-import-dependency/00-import-resource.yaml new file mode 100644 index 000000000..0681c805b --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/00-import-resource.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: user-import-dependency-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-dependency +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + domainRef: user-import-dependency \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/00-secret.yaml b/internal/controllers/user/tests/user-import-dependency/00-secret.yaml new file mode 100644 index 000000000..082860af5 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/01-assert.yaml b/internal/controllers/user/tests/user-import-dependency/01-assert.yaml new file mode 100644 index 000000000..eaa58861a --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/01-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-dependency-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-dependency +status: + conditions: + - type: Available + message: |- + Waiting for Domain/user-import-dependency to be ready + status: "False" + reason: Progressing + - type: Progressing + message: |- + Waiting for Domain/user-import-dependency to be ready + status: "True" + reason: Progressing \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/01-create-trap-resource.yaml b/internal/controllers/user/tests/user-import-dependency/01-create-trap-resource.yaml new file mode 100644 index 000000000..7154af7ba --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/01-create-trap-resource.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +# This `user-import-dependency-not-this-one` should not be picked by the import filter +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-dependency-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + domainRef: user-import-dependency-not-this-one \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/02-assert.yaml b/internal/controllers/user/tests/user-import-dependency/02-assert.yaml new file mode 100644 index 000000000..62decb321 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/02-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-import-dependency + ref: user1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-import-dependency-not-this-one + ref: user2 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-import-dependency + ref: domain +assertAll: + - celExpr: "user1.status.id != user2.status.id" + - celExpr: "user1.status.resource.domainID == domain.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-dependency +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/02-create-resource.yaml b/internal/controllers/user/tests/user-import-dependency/02-create-resource.yaml new file mode 100644 index 000000000..ea64cab75 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/02-create-resource.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-dependency-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + domainRef: user-import-dependency-external \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/03-assert.yaml b/internal/controllers/user/tests/user-import-dependency/03-assert.yaml new file mode 100644 index 000000000..32c8d86cd --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/03-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-import-dependency-external + ref: domain1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-import-dependency-not-this-one + ref: domain2 +assertAll: + - celExpr: "domain1.status.resource.enabled == false" + - celExpr: "domain2.status.resource.enabled == false" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/03-disable-domain.yaml b/internal/controllers/user/tests/user-import-dependency/03-disable-domain.yaml new file mode 100644 index 000000000..9265b4158 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/03-disable-domain.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-dependency-external +spec: + resource: + enabled: false +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-dependency-not-this-one +spec: + resource: + enabled: false \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/04-assert.yaml b/internal/controllers/user/tests/user-import-dependency/04-assert.yaml new file mode 100644 index 000000000..7c39b1cdb --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/04-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get domain.openstack.k-orc.cloud user-import-dependency --namespace $NAMESPACE" + skipLogOutput: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/04-delete-import-dependencies.yaml b/internal/controllers/user/tests/user-import-dependency/04-delete-import-dependencies.yaml new file mode 100644 index 000000000..32de53c66 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/04-delete-import-dependencies.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We should be able to delete the import dependencies + - command: kubectl delete domain.openstack.k-orc.cloud user-import-dependency + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/05-assert.yaml b/internal/controllers/user/tests/user-import-dependency/05-assert.yaml new file mode 100644 index 000000000..1f8812738 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/05-assert.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +- script: "! kubectl get user.openstack.k-orc.cloud user-import-dependency --namespace $NAMESPACE" + skipLogOutput: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/05-delete-resource.yaml b/internal/controllers/user/tests/user-import-dependency/05-delete-resource.yaml new file mode 100644 index 000000000..bebcdd8da --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/05-delete-resource.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-import-dependency \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-dependency/README.md b/internal/controllers/user/tests/user-import-dependency/README.md new file mode 100644 index 000000000..3f8526f24 --- /dev/null +++ b/internal/controllers/user/tests/user-import-dependency/README.md @@ -0,0 +1,33 @@ +# Check dependency handling for imported User + +## Step 00 + +Import a User that references other imported resources. The referenced imported resources have no matching resources yet. +Verify the User is waiting for the dependency to be ready. + +## Step 01 + +Create a User matching the import filter, except for referenced resources, and verify that it's not being imported. + +## Step 02 + +Create the referenced resources and a User matching the import filters. + +Verify that the observed status on the imported User corresponds to the spec of the created User. + +## Step 03 + +Disable the domain dependencies so KUTTL can clean the resources without failing. + +## Step 04 + +Delete the referenced resources and check that ORC does not prevent deletion. The OpenStack resources still exist because they +were imported resources and we only deleted the ORC representation of it. + +## Step 05 + +Delete the User and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-dependency \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-error/00-assert.yaml b/internal/controllers/user/tests/user-import-error/00-assert.yaml new file mode 100644 index 000000000..4efbfbde0 --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/00-assert.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-error-domain +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-error-external-1 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-error-external-2 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/user/tests/user-import-error/00-create-resources.yaml b/internal/controllers/user/tests/user-import-error/00-create-resources.yaml new file mode 100644 index 000000000..498801786 --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/00-create-resources.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-error-domain +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-error-external-1 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: User from "import error" test + domainRef: user-import-error-domain +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-error-external-2 +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: User from "import error" test + domainRef: user-import-error-domain \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-error/00-secret.yaml b/internal/controllers/user/tests/user-import-error/00-secret.yaml new file mode 100644 index 000000000..082860af5 --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-error/01-assert.yaml b/internal/controllers/user/tests/user-import-error/01-assert.yaml new file mode 100644 index 000000000..ddb4c0caf --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-error/01-import-resource.yaml b/internal/controllers/user/tests/user-import-error/01-import-resource.yaml new file mode 100644 index 000000000..6984d8c0b --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/01-import-resource.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-error +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + domainRef: user-import-error-domain \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-error/02-assert.yaml b/internal/controllers/user/tests/user-import-error/02-assert.yaml new file mode 100644 index 000000000..11d23cbeb --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/02-assert.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-import-error-domain + ref: domain +assertAll: + - celExpr: "domain.status.resource.enabled == false" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-error/02-disable-domain.yaml b/internal/controllers/user/tests/user-import-error/02-disable-domain.yaml new file mode 100644 index 000000000..e05ab92ce --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/02-disable-domain.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-error-domain +spec: + resource: + enabled: false \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import-error/README.md b/internal/controllers/user/tests/user-import-error/README.md new file mode 100644 index 000000000..3790cfe6e --- /dev/null +++ b/internal/controllers/user/tests/user-import-error/README.md @@ -0,0 +1,17 @@ +# Import User with more than one matching resources + +## Step 00 + +Create two Users with identical specs. + +## Step 01 + +Ensure that an imported User with a filter matching the resources returns an error. + +## Step 02 + +Disable the domain dependency so KUTTL can clean the resources without failing. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/00-assert.yaml b/internal/controllers/user/tests/user-import/00-assert.yaml new file mode 100644 index 000000000..44f6015ad --- /dev/null +++ b/internal/controllers/user/tests/user-import/00-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/00-import-resource.yaml b/internal/controllers/user/tests/user-import/00-import-resource.yaml new file mode 100644 index 000000000..d8b7199fa --- /dev/null +++ b/internal/controllers/user/tests/user-import/00-import-resource.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: user-import-external + domainRef: user-import-external \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/00-secret.yaml b/internal/controllers/user/tests/user-import/00-secret.yaml new file mode 100644 index 000000000..082860af5 --- /dev/null +++ b/internal/controllers/user/tests/user-import/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/01-assert.yaml b/internal/controllers/user/tests/user-import/01-assert.yaml new file mode 100644 index 000000000..bf4a0d9bc --- /dev/null +++ b/internal/controllers/user/tests/user-import/01-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-external-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: user-import-external-not-this-one + description: User user-import-external from "user-import" test +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/01-create-trap-resource.yaml b/internal/controllers/user/tests/user-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..ea393341f --- /dev/null +++ b/internal/controllers/user/tests/user-import/01-create-trap-resource.yaml @@ -0,0 +1,16 @@ +--- +# This `user-import-external-not-this-one` resource serves two purposes: +# - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) +# - ensure that importing a resource which name is a substring of it will not pick this one. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-external-not-this-one +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: User user-import-external from "user-import" test + domainRef: user-import-external \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/02-assert.yaml b/internal/controllers/user/tests/user-import/02-assert.yaml new file mode 100644 index 000000000..ec194ff34 --- /dev/null +++ b/internal/controllers/user/tests/user-import/02-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-import-external + ref: user1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-import-external-not-this-one + ref: user2 +assertAll: + - celExpr: "user1.status.id != user2.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: user-import-external + description: User user-import-external from "user-import" test + enabled: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/02-create-resource.yaml b/internal/controllers/user/tests/user-import/02-create-resource.yaml new file mode 100644 index 000000000..43a43ef04 --- /dev/null +++ b/internal/controllers/user/tests/user-import/02-create-resource.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-import-external +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + description: User user-import-external from "user-import" test + domainRef: user-import-external \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/03-assert.yaml b/internal/controllers/user/tests/user-import/03-assert.yaml new file mode 100644 index 000000000..2f7e63d0f --- /dev/null +++ b/internal/controllers/user/tests/user-import/03-assert.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Domain + name: user-import-external + ref: domain +assertAll: + - celExpr: "domain.status.resource.enabled == false" \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/03-disable-domain.yaml b/internal/controllers/user/tests/user-import/03-disable-domain.yaml new file mode 100644 index 000000000..aff09aed9 --- /dev/null +++ b/internal/controllers/user/tests/user-import/03-disable-domain.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Domain +metadata: + name: user-import-external +spec: + resource: + enabled: false \ No newline at end of file diff --git a/internal/controllers/user/tests/user-import/README.md b/internal/controllers/user/tests/user-import/README.md new file mode 100644 index 000000000..53be264fa --- /dev/null +++ b/internal/controllers/user/tests/user-import/README.md @@ -0,0 +1,22 @@ +# Import User + +## Step 00 + +Import a user that matches all fields in the filter, and verify it is waiting for the external resource to be created. + +## Step 01 + +Create a user whose name is a superstring of the one specified in the import filter, otherwise matching the filter, and verify that it's not being imported. + +## Step 02 + +Create a user matching the filter and verify that the observed status on the imported user corresponds to the spec of the created user. +Also, confirm that it does not adopt any user whose name is a superstring of its own. + +## Step 03 + +Disable the domain dependency so KUTTL can clean the resources without failing. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import \ No newline at end of file diff --git a/internal/controllers/user/tests/user-update/00-assert.yaml b/internal/controllers/user/tests/user-update/00-assert.yaml new file mode 100644 index 000000000..e30fd7137 --- /dev/null +++ b/internal/controllers/user/tests/user-update/00-assert.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-update + ref: user +assertAll: + - celExpr: "!has(user.status.resource.description)" + - celExpr: "user.status.resource.domainID == 'default'" + - celExpr: "!has(user.status.resource.defaultProjectID)" + # passwordExpiresAt depends on the Keystone security_compliance + # configuration and is not asserted here. + - celExpr: "user.status.resource.appliedPasswordRef == 'user-update'" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-update +status: + resource: + name: user-update + enabled: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success \ No newline at end of file diff --git a/internal/controllers/user/tests/user-update/00-minimal-resource.yaml b/internal/controllers/user/tests/user-update/00-minimal-resource.yaml new file mode 100644 index 000000000..d980e382a --- /dev/null +++ b/internal/controllers/user/tests/user-update/00-minimal-resource.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: user-update +type: Opaque +stringData: + password: "TestPassword" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-update +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + passwordRef: user-update \ No newline at end of file diff --git a/internal/controllers/user/tests/user-update/00-secret.yaml b/internal/controllers/user/tests/user-update/00-secret.yaml new file mode 100644 index 000000000..082860af5 --- /dev/null +++ b/internal/controllers/user/tests/user-update/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-update/01-assert.yaml b/internal/controllers/user/tests/user-update/01-assert.yaml new file mode 100644 index 000000000..cf594b6ee --- /dev/null +++ b/internal/controllers/user/tests/user-update/01-assert.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-update +status: + resource: + name: user-update-updated + description: user-update-updated + enabled: false + appliedPasswordRef: user-update-password-updated + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success \ No newline at end of file diff --git a/internal/controllers/user/tests/user-update/01-updated-resource.yaml b/internal/controllers/user/tests/user-update/01-updated-resource.yaml new file mode 100644 index 000000000..dd7727629 --- /dev/null +++ b/internal/controllers/user/tests/user-update/01-updated-resource.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: user-update-password-updated +type: Opaque +stringData: + password: "TestPasswordUpdated" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-update +spec: + resource: + name: user-update-updated + description: user-update-updated + enabled: false + passwordRef: user-update-password-updated diff --git a/internal/controllers/user/tests/user-update/02-assert.yaml b/internal/controllers/user/tests/user-update/02-assert.yaml new file mode 100644 index 000000000..7682f1636 --- /dev/null +++ b/internal/controllers/user/tests/user-update/02-assert.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: User + name: user-update + ref: user +assertAll: + - celExpr: "!has(user.status.resource.description)" + # passwordExpiresAt depends on the Keystone security_compliance + # configuration and is not asserted here. + - celExpr: "user.status.resource.appliedPasswordRef == 'user-update'" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: User +metadata: + name: user-update +status: + resource: + name: user-update + enabled: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success \ No newline at end of file diff --git a/internal/controllers/user/tests/user-update/02-reverted-resource.yaml b/internal/controllers/user/tests/user-update/02-reverted-resource.yaml new file mode 100644 index 000000000..ec043aae6 --- /dev/null +++ b/internal/controllers/user/tests/user-update/02-reverted-resource.yaml @@ -0,0 +1,7 @@ +# NOTE: kuttl only does patch updates, which means we can't delete a field. +# We have to use a kubectl apply command instead. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl replace -f 00-minimal-resource.yaml + namespaced: true \ No newline at end of file diff --git a/internal/controllers/user/tests/user-update/README.md b/internal/controllers/user/tests/user-update/README.md new file mode 100644 index 000000000..160b0122d --- /dev/null +++ b/internal/controllers/user/tests/user-update/README.md @@ -0,0 +1,17 @@ +# Update User + +## Step 00 + +Create a User using only mandatory fields. + +## Step 01 + +Update all mutable fields, including passwordRef (pointing to a new Secret). + +## Step 02 + +Revert the resource to its original value and verify that the resulting object matches its state when first created. + +## Reference + +https://k-orc.cloud/development/writing-tests/#update \ No newline at end of file diff --git a/internal/controllers/user/zz_generated.adapter.go b/internal/controllers/user/zz_generated.adapter.go new file mode 100644 index 000000000..fd800ac39 --- /dev/null +++ b/internal/controllers/user/zz_generated.adapter.go @@ -0,0 +1,98 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package user + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.User + orcObjectListT = orcv1alpha1.UserList + resourceSpecT = orcv1alpha1.UserResourceSpec + filterT = orcv1alpha1.UserFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = userAdapter +) + +type userAdapter struct { + *orcv1alpha1.User +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.User +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return f.Status.ID +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.ID +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} + +// getResourceName returns the name of the OpenStack resource we should use. +// This method is not implemented as part of APIObjectAdapter as it is intended +// to be used by resource actuators, which don't use the adapter. +func getResourceName(orcObject orcObjectPT) string { + if orcObject.Spec.Resource.Name != nil { + return string(*orcObject.Spec.Resource.Name) + } + return orcObject.Name +} diff --git a/internal/controllers/user/zz_generated.controller.go b/internal/controllers/user/zz_generated.controller.go new file mode 100644 index 000000000..667cf95e8 --- /dev/null +++ b/internal/controllers/user/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package user + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/controllers/volume/actuator.go b/internal/controllers/volume/actuator.go index 4e1e238f9..3b086ccc3 100644 --- a/internal/controllers/volume/actuator.go +++ b/internal/controllers/volume/actuator.go @@ -32,6 +32,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" ) @@ -155,9 +156,7 @@ func (actuator volumeActuator) CreateResource(ctx context.Context, obj orcObject var volumetypeID string if resource.VolumeTypeRef != nil { volumetype, volumetypeDepRS := volumetypeDependency.GetDependency( - ctx, actuator.k8sClient, obj, func(dep *orcv1alpha1.VolumeType) bool { - return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil - }, + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) reconcileStatus = reconcileStatus.WithReconcileStatus(volumetypeDepRS) if volumetype != nil { @@ -165,6 +164,15 @@ func (actuator volumeActuator) CreateResource(ctx context.Context, obj orcObject } } + // Resolve image dependency for bootable volumes + image, imageDepRS := dependency.FetchDependency[*orcv1alpha1.Image]( + ctx, actuator.k8sClient, obj.Namespace, + resource.ImageRef, "Image", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(imageDepRS) + imageID := ptr.Deref(image.Status.ID, "") + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { return nil, reconcileStatus } @@ -181,6 +189,7 @@ func (actuator volumeActuator) CreateResource(ctx context.Context, obj orcObject Metadata: metadata, VolumeType: volumetypeID, AvailabilityZone: resource.AvailabilityZone, + ImageID: imageID, } osResource, err := actuator.osClient.CreateVolume(ctx, createOpts) @@ -234,12 +243,10 @@ func (actuator volumeActuator) updateResource(ctx context.Context, obj orcObject _, err = actuator.osClient.UpdateVolume(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/volume/controller.go b/internal/controllers/volume/controller.go index 276c4236c..8c0d254ff 100644 --- a/internal/controllers/volume/controller.go +++ b/internal/controllers/volume/controller.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -51,17 +52,22 @@ const controllerName = "volume" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=volumes/status,verbs=get;update;patch type volumeReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return volumeReconcilerConstructor{scopeFactory: scopeFactory} + return &volumeReconcilerConstructor{scopeFactory: scopeFactory} } func (volumeReconcilerConstructor) GetName() string { return controllerName } +func (c *volumeReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + var volumetypeDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.VolumeList, *orcv1alpha1.VolumeType]( "spec.resource.volumeTypeRef", func(volume *orcv1alpha1.Volume) []string { @@ -74,6 +80,19 @@ var volumetypeDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.Vo finalizer, externalObjectFieldOwner, ) +// No deletion guard for image, because images can be safely deleted while +// referenced by a volume +var imageDependency = dependency.NewDependency[*orcv1alpha1.VolumeList, *orcv1alpha1.Image]( + "spec.resource.imageRef", + func(volume *orcv1alpha1.Volume) []string { + resource := volume.Spec.Resource + if resource == nil || resource.ImageRef == nil { + return nil + } + return []string{string(*resource.ImageRef)} + }, +) + // serverToVolumeMapFunc creates a mapping function that reconciles volumes when: // - a volume ID appears in server status but the volume doesn't have attachment info for that server // - a volume has attachment info for a server, but the server no longer lists that volume @@ -149,6 +168,12 @@ func serverToVolumeMapFunc(ctx context.Context, k8sClient client.Client) handler log.V(logging.Verbose).Info("volume needs reconciliation: listed in server status but no attachment info", "volume", client.ObjectKeyFromObject(volume), "server", client.ObjectKeyFromObject(server)) + } else if volumeStatus.Status != VolumeStatusInUse { + shouldReconcile = true + reason = "Volume attached to server but status is not in-use" + log.V(logging.Verbose).Info("volume needs reconciliation: attached to server but status is not in-use", + "volume", client.ObjectKeyFromObject(volume), + "server", client.ObjectKeyFromObject(server)) } } @@ -200,7 +225,7 @@ func serverToVolumeMapFunc(ctx context.Context, k8sClient client.Client) handler } // SetupWithManager sets up the controller with the Manager. -func (c volumeReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *volumeReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) k8sClient := mgr.GetClient() @@ -209,11 +234,19 @@ func (c volumeReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c return err } + imageWatchEventHandler, err := imageDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + builder := ctrl.NewControllerManagedBy(mgr). WithOptions(options). Watches(&orcv1alpha1.VolumeType{}, volumetypeWatchEventHandler, builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.VolumeType{})), ). + Watches(&orcv1alpha1.Image{}, imageWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Image{})), + ). Watches(&orcv1alpha1.Server{}, handler.EnqueueRequestsFromMapFunc(serverToVolumeMapFunc(ctx, k8sClient)), builder.WithPredicates(predicates.NewServerVolumesChanged(log)), ). @@ -221,12 +254,13 @@ func (c volumeReconcilerConstructor) SetupWithManager(ctx context.Context, mgr c if err := errors.Join( volumetypeDependency.AddToManager(ctx, mgr), + imageDependency.AddToManager(ctx, mgr), credentialsDependency.AddToManager(ctx, mgr), credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), ); err != nil { return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, volumeHelperFactory{}, volumeStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, volumeHelperFactory{}, volumeStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/volume/status.go b/internal/controllers/volume/status.go index 064ef7575..96de129be 100644 --- a/internal/controllers/volume/status.go +++ b/internal/controllers/volume/status.go @@ -92,6 +92,13 @@ func (volumeStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osRes } } + // Extract image ID from volume_image_metadata if present. + // When a volume is created from an image, OpenStack stores the source + // image ID in the volume's metadata under "image_id". + if imageID, ok := osResource.VolumeImageMetadata["image_id"]; ok { + resourceStatus.WithImageID(imageID) + } + for k, v := range osResource.Metadata { resourceStatus.WithMetadata(orcapplyconfigv1alpha1.VolumeMetadataStatus(). WithName(k). diff --git a/internal/controllers/volume/tests/volume-dependency/00-assert.yaml b/internal/controllers/volume/tests/volume-dependency/00-assert.yaml index 92782c001..bd0a875de 100644 --- a/internal/controllers/volume/tests/volume-dependency/00-assert.yaml +++ b/internal/controllers/volume/tests/volume-dependency/00-assert.yaml @@ -28,3 +28,18 @@ status: message: Waiting for VolumeType/volume-dependency to be created status: "True" reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Volume +metadata: + name: volume-dependency-no-image +status: + conditions: + - type: Available + message: Waiting for Image/volume-dependency-image to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Image/volume-dependency-image to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/volume/tests/volume-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/volume/tests/volume-dependency/00-create-resources-missing-deps.yaml index ac339b291..bf7498567 100644 --- a/internal/controllers/volume/tests/volume-dependency/00-create-resources-missing-deps.yaml +++ b/internal/controllers/volume/tests/volume-dependency/00-create-resources-missing-deps.yaml @@ -23,3 +23,16 @@ spec: managementPolicy: managed resource: size: 1 +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Volume +metadata: + name: volume-dependency-no-image +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + size: 1 + imageRef: volume-dependency-image diff --git a/internal/controllers/volume/tests/volume-dependency/01-assert.yaml b/internal/controllers/volume/tests/volume-dependency/01-assert.yaml index df8013931..bc42ce16e 100644 --- a/internal/controllers/volume/tests/volume-dependency/01-assert.yaml +++ b/internal/controllers/volume/tests/volume-dependency/01-assert.yaml @@ -28,3 +28,20 @@ status: message: OpenStack resource is up to date status: "False" reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Volume +metadata: + name: volume-dependency-no-image +status: + resource: + size: 1 + status: available + bootable: true + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/volume/tests/volume-dependency/01-create-dependencies.yaml b/internal/controllers/volume/tests/volume-dependency/01-create-dependencies.yaml index 48f733a40..8614ae18b 100644 --- a/internal/controllers/volume/tests/volume-dependency/01-create-dependencies.yaml +++ b/internal/controllers/volume/tests/volume-dependency/01-create-dependencies.yaml @@ -15,3 +15,18 @@ spec: secretName: openstack-clouds managementPolicy: managed resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Image +metadata: + name: volume-dependency-image +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + content: + diskFormat: raw + download: + url: https://github.com/k-orc/openstack-resource-controller/raw/690b760f49dfb61b173755e91cb51ed42472c7f3/internal/controllers/image/testdata/raw.img diff --git a/internal/controllers/volume/tests/volume-dependency/02-assert.yaml b/internal/controllers/volume/tests/volume-dependency/02-assert.yaml index 03226f163..b0ad37076 100644 --- a/internal/controllers/volume/tests/volume-dependency/02-assert.yaml +++ b/internal/controllers/volume/tests/volume-dependency/02-assert.yaml @@ -15,3 +15,7 @@ assertAll: - celExpr: "'openstack.k-orc.cloud/volume' in volumetype.metadata.finalizers" - celExpr: "secret.metadata.deletionTimestamp != 0" - celExpr: "'openstack.k-orc.cloud/volume' in secret.metadata.finalizers" +commands: +# Image is a creation dependency, so it should be deleted immediately +- script: "! kubectl get image volume-dependency-image --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/volume/tests/volume-dependency/02-delete-dependencies.yaml b/internal/controllers/volume/tests/volume-dependency/02-delete-dependencies.yaml index e1a57dbca..ed31865bd 100644 --- a/internal/controllers/volume/tests/volume-dependency/02-delete-dependencies.yaml +++ b/internal/controllers/volume/tests/volume-dependency/02-delete-dependencies.yaml @@ -7,3 +7,5 @@ commands: namespaced: true - command: kubectl delete secret volume-dependency --wait=false namespaced: true + - command: kubectl delete image volume-dependency-image --wait=false + namespaced: true diff --git a/internal/controllers/volume/tests/volume-dependency/03-delete-resources.yaml b/internal/controllers/volume/tests/volume-dependency/03-delete-resources.yaml index 029d18239..d6522eb2b 100644 --- a/internal/controllers/volume/tests/volume-dependency/03-delete-resources.yaml +++ b/internal/controllers/volume/tests/volume-dependency/03-delete-resources.yaml @@ -8,3 +8,6 @@ delete: - apiVersion: openstack.k-orc.cloud/v1alpha1 kind: Volume name: volume-dependency-no-volumetype +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Volume + name: volume-dependency-no-image diff --git a/internal/controllers/volume/tests/volume-dependency/README.md b/internal/controllers/volume/tests/volume-dependency/README.md index 1cb2029b1..b9d398843 100644 --- a/internal/controllers/volume/tests/volume-dependency/README.md +++ b/internal/controllers/volume/tests/volume-dependency/README.md @@ -10,11 +10,13 @@ Create the missing dependencies and make and verify all the Volumes are availabl ## Step 02 -Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. +Delete all the dependencies and check: +- VolumeType and Secret have finalizers preventing deletion (hard dependencies) +- Image is deleted immediately (soft dependency - no finalizer) ## Step 03 -Delete the Volumes and validate that all resources are gone. +Delete the Volumes and validate that VolumeType and Secret are now gone. ## Reference diff --git a/internal/controllers/volume/zz_generated.adapter.go b/internal/controllers/volume/zz_generated.adapter.go index fe9aebdd1..6acc67b2b 100644 --- a/internal/controllers/volume/zz_generated.adapter.go +++ b/internal/controllers/volume/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package volume import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/volume/zz_generated.controller.go b/internal/controllers/volume/zz_generated.controller.go index d4585cef1..080ff160c 100644 --- a/internal/controllers/volume/zz_generated.controller.go +++ b/internal/controllers/volume/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/controllers/volumetype/actuator.go b/internal/controllers/volumetype/actuator.go index 8ba83f033..85c5ed503 100644 --- a/internal/controllers/volumetype/actuator.go +++ b/internal/controllers/volumetype/actuator.go @@ -202,12 +202,10 @@ func (actuator volumetypeActuator) updateResource(ctx context.Context, obj orcOb _, err = actuator.osClient.UpdateVolumeType(ctx, osResource.ID, updateOpts) - // We should require the spec to be updated before retrying an update which returned a conflict - if orcerrors.IsConflict(err) { - err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) - } - if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } return progress.WrapError(err) } diff --git a/internal/controllers/volumetype/controller.go b/internal/controllers/volumetype/controller.go index 45707166a..a358a6d2d 100644 --- a/internal/controllers/volumetype/controller.go +++ b/internal/controllers/volumetype/controller.go @@ -19,6 +19,7 @@ package volumetype import ( "context" "errors" + "time" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -36,19 +37,24 @@ const controllerName = "volumetype" // +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=volumetypes/status,verbs=get;update;patch type volumetypeReconcilerConstructor struct { - scopeFactory scope.Factory + scopeFactory scope.Factory + defaultResyncPeriod time.Duration } func New(scopeFactory scope.Factory) interfaces.Controller { - return volumetypeReconcilerConstructor{scopeFactory: scopeFactory} + return &volumetypeReconcilerConstructor{scopeFactory: scopeFactory} } func (volumetypeReconcilerConstructor) GetName() string { return controllerName } +func (c *volumetypeReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + // SetupWithManager sets up the controller with the Manager. -func (c volumetypeReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { +func (c *volumetypeReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { log := ctrl.LoggerFrom(ctx) builder := ctrl.NewControllerManagedBy(mgr). @@ -62,6 +68,6 @@ func (c volumetypeReconcilerConstructor) SetupWithManager(ctx context.Context, m return err } - r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, volumetypeHelperFactory{}, volumetypeStatusWriter{}) + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, volumetypeHelperFactory{}, volumetypeStatusWriter{}, c.defaultResyncPeriod) return builder.Complete(&r) } diff --git a/internal/controllers/volumetype/zz_generated.adapter.go b/internal/controllers/volumetype/zz_generated.adapter.go index 2490ef70e..ac8f117d5 100644 --- a/internal/controllers/volumetype/zz_generated.adapter.go +++ b/internal/controllers/volumetype/zz_generated.adapter.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ limitations under the License. package volumetype import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" ) @@ -55,6 +57,14 @@ func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { return f.Spec.ManagedOptions } +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + func (f adapterT) GetStatusID() *string { return f.Status.ID } diff --git a/internal/controllers/volumetype/zz_generated.controller.go b/internal/controllers/volumetype/zz_generated.controller.go index 0e551e2f2..74d96c985 100644 --- a/internal/controllers/volumetype/zz_generated.controller.go +++ b/internal/controllers/volumetype/zz_generated.controller.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/manager/manager.go b/internal/manager/manager.go index ea84eb77f..e8d5932c9 100644 --- a/internal/manager/manager.go +++ b/internal/manager/manager.go @@ -20,6 +20,7 @@ import ( "context" "crypto/tls" "fmt" + "time" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -49,8 +50,11 @@ type Options struct { TLSOpts []func(*tls.Config) ScopeCacheMaxSize int WatchNamespaces []string + DefaultResyncPeriod time.Duration } +const lowDefaultResyncPeriodWarningThreshold = 2 * time.Minute + func Run(ctx context.Context, opts *Options, restConfig *rest.Config, scheme *runtime.Scheme, setupLog, log logr.Logger, controllers []interfaces.Controller) error { // if the enable-http2 flag is false (the default), http/2 should be disabled // due to its vulnerabilities. More specifically, disabling http/2 will @@ -141,7 +145,14 @@ func Run(ctx context.Context, opts *Options, restConfig *rest.Config, scheme *ru return fmt.Errorf("unable to set up ready check: %w", err) } + if opts.DefaultResyncPeriod > 0 && opts.DefaultResyncPeriod < lowDefaultResyncPeriodWarningThreshold { + setupLog.Info("warning: default resync period is very low and may cause excessive OpenStack API load", + "defaultResyncPeriod", opts.DefaultResyncPeriod.String(), + "recommendedMinimum", lowDefaultResyncPeriodWarningThreshold.String()) + } + for _, c := range controllers { + c.SetDefaultResyncPeriod(opts.DefaultResyncPeriod) if err := c.SetupWithManager(ctx, mgr, controller.Options{}); err != nil { return fmt.Errorf("unable to create %s controller: %w", c.GetName(), err) } diff --git a/internal/osclients/addressscope.go b/internal/osclients/addressscope.go new file mode 100644 index 000000000..464628e0b --- /dev/null +++ b/internal/osclients/addressscope.go @@ -0,0 +1,104 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osclients + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/addressscopes" + "github.com/gophercloud/utils/v2/openstack/clientconfig" +) + +type AddressScopeClient interface { + ListAddressScopes(ctx context.Context, listOpts addressscopes.ListOptsBuilder) iter.Seq2[*addressscopes.AddressScope, error] + CreateAddressScope(ctx context.Context, opts addressscopes.CreateOptsBuilder) (*addressscopes.AddressScope, error) + DeleteAddressScope(ctx context.Context, resourceID string) error + GetAddressScope(ctx context.Context, resourceID string) (*addressscopes.AddressScope, error) + UpdateAddressScope(ctx context.Context, id string, opts addressscopes.UpdateOptsBuilder) (*addressscopes.AddressScope, error) +} + +type addressscopeClient struct{ client *gophercloud.ServiceClient } + +// NewAddressScopeClient returns a new OpenStack client. +func NewAddressScopeClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (AddressScopeClient, error) { + client, err := openstack.NewNetworkV2(providerClient, gophercloud.EndpointOpts{ + Region: providerClientOpts.RegionName, + Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType), + }) + + if err != nil { + return nil, fmt.Errorf("failed to create addressscope service client: %v", err) + } + + return &addressscopeClient{client}, nil +} + +func (c addressscopeClient) ListAddressScopes(ctx context.Context, listOpts addressscopes.ListOptsBuilder) iter.Seq2[*addressscopes.AddressScope, error] { + pager := addressscopes.List(c.client, listOpts) + return func(yield func(*addressscopes.AddressScope, error) bool) { + _ = pager.EachPage(ctx, yieldPage(addressscopes.ExtractAddressScopes, yield)) + } +} + +func (c addressscopeClient) CreateAddressScope(ctx context.Context, opts addressscopes.CreateOptsBuilder) (*addressscopes.AddressScope, error) { + return addressscopes.Create(ctx, c.client, opts).Extract() +} + +func (c addressscopeClient) DeleteAddressScope(ctx context.Context, resourceID string) error { + return addressscopes.Delete(ctx, c.client, resourceID).ExtractErr() +} + +func (c addressscopeClient) GetAddressScope(ctx context.Context, resourceID string) (*addressscopes.AddressScope, error) { + return addressscopes.Get(ctx, c.client, resourceID).Extract() +} + +func (c addressscopeClient) UpdateAddressScope(ctx context.Context, id string, opts addressscopes.UpdateOptsBuilder) (*addressscopes.AddressScope, error) { + return addressscopes.Update(ctx, c.client, id, opts).Extract() +} + +type addressscopeErrorClient struct{ error } + +// NewAddressScopeErrorClient returns a AddressScopeClient in which every method returns the given error. +func NewAddressScopeErrorClient(e error) AddressScopeClient { + return addressscopeErrorClient{e} +} + +func (e addressscopeErrorClient) ListAddressScopes(_ context.Context, _ addressscopes.ListOptsBuilder) iter.Seq2[*addressscopes.AddressScope, error] { + return func(yield func(*addressscopes.AddressScope, error) bool) { + yield(nil, e.error) + } +} + +func (e addressscopeErrorClient) CreateAddressScope(_ context.Context, _ addressscopes.CreateOptsBuilder) (*addressscopes.AddressScope, error) { + return nil, e.error +} + +func (e addressscopeErrorClient) DeleteAddressScope(_ context.Context, _ string) error { + return e.error +} + +func (e addressscopeErrorClient) GetAddressScope(_ context.Context, _ string) (*addressscopes.AddressScope, error) { + return nil, e.error +} + +func (e addressscopeErrorClient) UpdateAddressScope(_ context.Context, _ string, _ addressscopes.UpdateOptsBuilder) (*addressscopes.AddressScope, error) { + return nil, e.error +} diff --git a/internal/osclients/applicationcredential.go b/internal/osclients/applicationcredential.go new file mode 100644 index 000000000..30c63adad --- /dev/null +++ b/internal/osclients/applicationcredential.go @@ -0,0 +1,156 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osclients + +import ( + "context" + "errors" + "fmt" + "iter" + + tokens3 "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/applicationcredentials" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/users" + "github.com/gophercloud/utils/v2/openstack/clientconfig" +) + +type ApplicationCredentialClient interface { + ListApplicationCredentials(ctx context.Context, userID string, listOpts applicationcredentials.ListOptsBuilder) iter.Seq2[*applicationcredentials.ApplicationCredential, error] + CreateApplicationCredential(ctx context.Context, userID string, opts applicationcredentials.CreateOptsBuilder) (*applicationcredentials.ApplicationCredential, error) + DeleteApplicationCredential(ctx context.Context, userID string, resourceID string) error + GetApplicationCredential(ctx context.Context, resourceID string) (*applicationcredentials.ApplicationCredential, error) +} + +type applicationcredentialClient struct{ client *gophercloud.ServiceClient } + +// NewApplicationCredentialClient returns a new OpenStack client. +func NewApplicationCredentialClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (ApplicationCredentialClient, error) { + client, err := openstack.NewIdentityV3(providerClient, gophercloud.EndpointOpts{ + Region: providerClientOpts.RegionName, + Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType), + }) + + if err != nil { + return nil, fmt.Errorf("failed to create applicationcredential service client: %v", err) + } + + return &applicationcredentialClient{client}, nil +} + +func (c applicationcredentialClient) ListApplicationCredentials(ctx context.Context, userID string, listOpts applicationcredentials.ListOptsBuilder) iter.Seq2[*applicationcredentials.ApplicationCredential, error] { + pager := applicationcredentials.List(c.client, userID, listOpts) + return func(yield func(*applicationcredentials.ApplicationCredential, error) bool) { + _ = pager.EachPage(ctx, yieldPage(applicationcredentials.ExtractApplicationCredentials, yield)) + } +} + +func (c applicationcredentialClient) CreateApplicationCredential(ctx context.Context, userID string, opts applicationcredentials.CreateOptsBuilder) (*applicationcredentials.ApplicationCredential, error) { + return applicationcredentials.Create(ctx, c.client, userID, opts).Extract() +} + +func (c applicationcredentialClient) DeleteApplicationCredential(ctx context.Context, userID string, resourceID string) error { + return applicationcredentials.Delete(ctx, c.client, userID, resourceID).ExtractErr() +} + +func (c applicationcredentialClient) GetApplicationCredential(ctx context.Context, resourceID string) (*applicationcredentials.ApplicationCredential, error) { + // The unique ID of an application credential is not enough to query it from OpenStack + // OpenStack actually also requires a unique user ID. + // We can not provide the user ID here, as the function signatures of ORC interfaces + // expect us to return an OpenStack resource based on a single string. + + // To work around this, we first query ApplicationCredentials for the currently + // authenticated user which ORC is connected as. If that fails, we iterate over + // all users we have access to and query their ApplicationCredentials. + + // Currently authenticated user + userID, err := GetAuthenticatedUserID(c.client.ProviderClient) + if err == nil { + appCred, appCredErr := applicationcredentials.Get(ctx, c.client, userID, resourceID).Extract() + + if appCred != nil { + return appCred, appCredErr + } + } + + // If not found in currently authenticated user, try iterating over all users + userPager := users.List(c.client, nil) + userIterator := func(yield func(*users.User, error) bool) { + _ = userPager.EachPage(ctx, yieldPage(users.ExtractUsers, yield)) + } + + for user, userErr := range userIterator { + if userErr != nil { + continue + } + + appCred, appCredErr := applicationcredentials.Get(ctx, c.client, user.ID, resourceID).Extract() + + if appCred != nil { + return appCred, appCredErr + } + } + + return nil, gophercloud.ErrResourceNotFound{ + Name: resourceID, + ResourceType: "ApplicationCredential", + } +} + +func GetAuthenticatedUserID(providerClient *gophercloud.ProviderClient) (string, error) { + r := providerClient.GetAuthResult() + if r == nil { + return "", errors.New("no AuthResult available") + } + switch r := r.(type) { + case tokens3.CreateResult: + u, err := r.ExtractUser() + if err != nil { + return "", err + } + return u.ID, nil + default: + return "", errors.New("wrong AuthResult version") + } +} + +type applicationcredentialErrorClient struct{ error } + +// NewApplicationCredentialErrorClient returns a ApplicationCredentialClient in which every method returns the given error. +func NewApplicationCredentialErrorClient(e error) ApplicationCredentialClient { + return applicationcredentialErrorClient{e} +} + +func (e applicationcredentialErrorClient) ListApplicationCredentials(_ context.Context, _ string, _ applicationcredentials.ListOptsBuilder) iter.Seq2[*applicationcredentials.ApplicationCredential, error] { + return func(yield func(*applicationcredentials.ApplicationCredential, error) bool) { + yield(nil, e.error) + } +} + +func (e applicationcredentialErrorClient) CreateApplicationCredential(_ context.Context, _ string, _ applicationcredentials.CreateOptsBuilder) (*applicationcredentials.ApplicationCredential, error) { + return nil, e.error +} + +func (e applicationcredentialErrorClient) DeleteApplicationCredential(_ context.Context, _ string, _ string) error { + return e.error +} + +func (e applicationcredentialErrorClient) GetApplicationCredential(_ context.Context, _ string) (*applicationcredentials.ApplicationCredential, error) { + return nil, e.error +} diff --git a/internal/osclients/compute.go b/internal/osclients/compute.go index e40154150..59bec1621 100644 --- a/internal/osclients/compute.go +++ b/internal/osclients/compute.go @@ -49,8 +49,10 @@ const NovaMinimumMicroversion = "2.71" type ComputeClient interface { CreateFlavor(ctx context.Context, opts flavors.CreateOptsBuilder) (*flavors.Flavor, error) + CreateFlavorExtraSpecs(ctx context.Context, id string, opts flavors.CreateExtraSpecsOptsBuilder) (map[string]string, error) GetFlavor(ctx context.Context, id string) (*flavors.Flavor, error) DeleteFlavor(ctx context.Context, id string) error + DeleteFlavorExtraSpec(ctx context.Context, id, key string) error ListFlavors(ctx context.Context, listOpts flavors.ListOptsBuilder) iter.Seq2[*flavors.Flavor, error] CreateServer(ctx context.Context, createOpts servers.CreateOptsBuilder, schedulerHints servers.SchedulerHintOptsBuilder) (*servers.Server, error) @@ -72,6 +74,7 @@ type ComputeClient interface { DeleteAttachedInterface(ctx context.Context, serverID, portID string) error ReplaceAllServerAttributesTags(ctx context.Context, resourceID string, opts tags.ReplaceAllOptsBuilder) ([]string, error) + ReplaceServerMetadata(ctx context.Context, serverID string, opts servers.MetadataOpts) (map[string]string, error) } type computeClient struct{ client *gophercloud.ServiceClient } @@ -106,10 +109,18 @@ func (c computeClient) CreateFlavor(ctx context.Context, opts flavors.CreateOpts return flavors.Create(ctx, c.client, opts).Extract() } +func (c computeClient) CreateFlavorExtraSpecs(ctx context.Context, id string, opts flavors.CreateExtraSpecsOptsBuilder) (map[string]string, error) { + return flavors.CreateExtraSpecs(ctx, c.client, id, opts).Extract() +} + func (c computeClient) DeleteFlavor(ctx context.Context, id string) error { return flavors.Delete(ctx, c.client, id).ExtractErr() } +func (c computeClient) DeleteFlavorExtraSpec(ctx context.Context, id, key string) error { + return flavors.DeleteExtraSpec(ctx, c.client, id, key).ExtractErr() +} + func (c computeClient) ListFlavors(ctx context.Context, opts flavors.ListOptsBuilder) iter.Seq2[*flavors.Flavor, error] { pager := flavors.ListDetail(c.client, opts) return func(yield func(*flavors.Flavor, error) bool) { @@ -187,6 +198,10 @@ func (c computeClient) ReplaceAllServerAttributesTags(ctx context.Context, resou return tags.ReplaceAll(ctx, c.client, resourceID, opts).Extract() } +func (c computeClient) ReplaceServerMetadata(ctx context.Context, serverID string, opts servers.MetadataOpts) (map[string]string, error) { + return servers.ResetMetadata(ctx, c.client, serverID, opts).Extract() +} + type computeErrorClient struct{ error } // NewComputeErrorClient returns a ComputeClient in which every method returns the given error. @@ -196,12 +211,18 @@ func NewComputeErrorClient(e error) ComputeClient { func (e computeErrorClient) CreateFlavor(ctx context.Context, opts flavors.CreateOptsBuilder) (*flavors.Flavor, error) { return nil, e.error } +func (e computeErrorClient) CreateFlavorExtraSpecs(ctx context.Context, id string, opts flavors.CreateExtraSpecsOptsBuilder) (map[string]string, error) { + return nil, e.error +} func (e computeErrorClient) GetFlavor(ctx context.Context, id string) (*flavors.Flavor, error) { return nil, e.error } func (e computeErrorClient) DeleteFlavor(ctx context.Context, id string) error { return e.error } +func (e computeErrorClient) DeleteFlavorExtraSpec(ctx context.Context, id, key string) error { + return e.error +} func (e computeErrorClient) ListFlavors(_ context.Context, _ flavors.ListOptsBuilder) iter.Seq2[*flavors.Flavor, error] { return func(yield func(*flavors.Flavor, error) bool) { yield(nil, e.error) @@ -275,3 +296,7 @@ func (e computeErrorClient) DeleteAttachedInterface(_ context.Context, _, _ stri func (e computeErrorClient) ReplaceAllServerAttributesTags(_ context.Context, _ string, _ tags.ReplaceAllOptsBuilder) ([]string, error) { return nil, e.error } + +func (e computeErrorClient) ReplaceServerMetadata(_ context.Context, _ string, _ servers.MetadataOpts) (map[string]string, error) { + return nil, e.error +} diff --git a/internal/osclients/endpoint.go b/internal/osclients/endpoint.go new file mode 100644 index 000000000..df0c7c1f9 --- /dev/null +++ b/internal/osclients/endpoint.go @@ -0,0 +1,104 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osclients + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/endpoints" + "github.com/gophercloud/utils/v2/openstack/clientconfig" +) + +type EndpointClient interface { + ListEndpoints(ctx context.Context, listOpts endpoints.ListOptsBuilder) iter.Seq2[*endpoints.Endpoint, error] + CreateEndpoint(ctx context.Context, opts endpoints.CreateOptsBuilder) (*endpoints.Endpoint, error) + DeleteEndpoint(ctx context.Context, resourceID string) error + GetEndpoint(ctx context.Context, resourceID string) (*endpoints.Endpoint, error) + UpdateEndpoint(ctx context.Context, id string, opts endpoints.UpdateOptsBuilder) (*endpoints.Endpoint, error) +} + +type endpointClient struct{ client *gophercloud.ServiceClient } + +// NewEndpointClient returns a new OpenStack client. +func NewEndpointClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (EndpointClient, error) { + client, err := openstack.NewIdentityV3(providerClient, gophercloud.EndpointOpts{ + Region: providerClientOpts.RegionName, + Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType), + }) + + if err != nil { + return nil, fmt.Errorf("failed to create endpoint service client: %v", err) + } + + return &endpointClient{client}, nil +} + +func (c endpointClient) ListEndpoints(ctx context.Context, listOpts endpoints.ListOptsBuilder) iter.Seq2[*endpoints.Endpoint, error] { + pager := endpoints.List(c.client, listOpts) + return func(yield func(*endpoints.Endpoint, error) bool) { + _ = pager.EachPage(ctx, yieldPage(endpoints.ExtractEndpoints, yield)) + } +} + +func (c endpointClient) CreateEndpoint(ctx context.Context, opts endpoints.CreateOptsBuilder) (*endpoints.Endpoint, error) { + return endpoints.Create(ctx, c.client, opts).Extract() +} + +func (c endpointClient) DeleteEndpoint(ctx context.Context, resourceID string) error { + return endpoints.Delete(ctx, c.client, resourceID).ExtractErr() +} + +func (c endpointClient) GetEndpoint(ctx context.Context, resourceID string) (*endpoints.Endpoint, error) { + return endpoints.Get(ctx, c.client, resourceID).Extract() +} + +func (c endpointClient) UpdateEndpoint(ctx context.Context, id string, opts endpoints.UpdateOptsBuilder) (*endpoints.Endpoint, error) { + return endpoints.Update(ctx, c.client, id, opts).Extract() +} + +type endpointErrorClient struct{ error } + +// NewEndpointErrorClient returns a EndpointClient in which every method returns the given error. +func NewEndpointErrorClient(e error) EndpointClient { + return endpointErrorClient{e} +} + +func (e endpointErrorClient) ListEndpoints(_ context.Context, _ endpoints.ListOptsBuilder) iter.Seq2[*endpoints.Endpoint, error] { + return func(yield func(*endpoints.Endpoint, error) bool) { + yield(nil, e.error) + } +} + +func (e endpointErrorClient) CreateEndpoint(_ context.Context, _ endpoints.CreateOptsBuilder) (*endpoints.Endpoint, error) { + return nil, e.error +} + +func (e endpointErrorClient) DeleteEndpoint(_ context.Context, _ string) error { + return e.error +} + +func (e endpointErrorClient) GetEndpoint(_ context.Context, _ string) (*endpoints.Endpoint, error) { + return nil, e.error +} + +func (e endpointErrorClient) UpdateEndpoint(_ context.Context, _ string, _ endpoints.UpdateOptsBuilder) (*endpoints.Endpoint, error) { + return nil, e.error +} diff --git a/internal/osclients/mock/addressscope.go b/internal/osclients/mock/addressscope.go new file mode 100644 index 000000000..fbaf844bb --- /dev/null +++ b/internal/osclients/mock/addressscope.go @@ -0,0 +1,131 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../addressscope.go +// +// Generated by this command: +// +// mockgen -package mock -destination=addressscope.go -source=../addressscope.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock AddressScopeClient +// + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + iter "iter" + reflect "reflect" + + addressscopes "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/addressscopes" + gomock "go.uber.org/mock/gomock" +) + +// MockAddressScopeClient is a mock of AddressScopeClient interface. +type MockAddressScopeClient struct { + ctrl *gomock.Controller + recorder *MockAddressScopeClientMockRecorder + isgomock struct{} +} + +// MockAddressScopeClientMockRecorder is the mock recorder for MockAddressScopeClient. +type MockAddressScopeClientMockRecorder struct { + mock *MockAddressScopeClient +} + +// NewMockAddressScopeClient creates a new mock instance. +func NewMockAddressScopeClient(ctrl *gomock.Controller) *MockAddressScopeClient { + mock := &MockAddressScopeClient{ctrl: ctrl} + mock.recorder = &MockAddressScopeClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAddressScopeClient) EXPECT() *MockAddressScopeClientMockRecorder { + return m.recorder +} + +// CreateAddressScope mocks base method. +func (m *MockAddressScopeClient) CreateAddressScope(ctx context.Context, opts addressscopes.CreateOptsBuilder) (*addressscopes.AddressScope, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateAddressScope", ctx, opts) + ret0, _ := ret[0].(*addressscopes.AddressScope) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateAddressScope indicates an expected call of CreateAddressScope. +func (mr *MockAddressScopeClientMockRecorder) CreateAddressScope(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAddressScope", reflect.TypeOf((*MockAddressScopeClient)(nil).CreateAddressScope), ctx, opts) +} + +// DeleteAddressScope mocks base method. +func (m *MockAddressScopeClient) DeleteAddressScope(ctx context.Context, resourceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAddressScope", ctx, resourceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteAddressScope indicates an expected call of DeleteAddressScope. +func (mr *MockAddressScopeClientMockRecorder) DeleteAddressScope(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAddressScope", reflect.TypeOf((*MockAddressScopeClient)(nil).DeleteAddressScope), ctx, resourceID) +} + +// GetAddressScope mocks base method. +func (m *MockAddressScopeClient) GetAddressScope(ctx context.Context, resourceID string) (*addressscopes.AddressScope, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAddressScope", ctx, resourceID) + ret0, _ := ret[0].(*addressscopes.AddressScope) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAddressScope indicates an expected call of GetAddressScope. +func (mr *MockAddressScopeClientMockRecorder) GetAddressScope(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAddressScope", reflect.TypeOf((*MockAddressScopeClient)(nil).GetAddressScope), ctx, resourceID) +} + +// ListAddressScopes mocks base method. +func (m *MockAddressScopeClient) ListAddressScopes(ctx context.Context, listOpts addressscopes.ListOptsBuilder) iter.Seq2[*addressscopes.AddressScope, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListAddressScopes", ctx, listOpts) + ret0, _ := ret[0].(iter.Seq2[*addressscopes.AddressScope, error]) + return ret0 +} + +// ListAddressScopes indicates an expected call of ListAddressScopes. +func (mr *MockAddressScopeClientMockRecorder) ListAddressScopes(ctx, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAddressScopes", reflect.TypeOf((*MockAddressScopeClient)(nil).ListAddressScopes), ctx, listOpts) +} + +// UpdateAddressScope mocks base method. +func (m *MockAddressScopeClient) UpdateAddressScope(ctx context.Context, id string, opts addressscopes.UpdateOptsBuilder) (*addressscopes.AddressScope, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateAddressScope", ctx, id, opts) + ret0, _ := ret[0].(*addressscopes.AddressScope) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateAddressScope indicates an expected call of UpdateAddressScope. +func (mr *MockAddressScopeClientMockRecorder) UpdateAddressScope(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAddressScope", reflect.TypeOf((*MockAddressScopeClient)(nil).UpdateAddressScope), ctx, id, opts) +} diff --git a/internal/osclients/mock/applicationcredential.go b/internal/osclients/mock/applicationcredential.go new file mode 100644 index 000000000..cecd4726e --- /dev/null +++ b/internal/osclients/mock/applicationcredential.go @@ -0,0 +1,116 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../applicationcredential.go +// +// Generated by this command: +// +// mockgen -package mock -destination=applicationcredential.go -source=../applicationcredential.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock ApplicationCredentialClient +// + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + iter "iter" + reflect "reflect" + + applicationcredentials "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/applicationcredentials" + gomock "go.uber.org/mock/gomock" +) + +// MockApplicationCredentialClient is a mock of ApplicationCredentialClient interface. +type MockApplicationCredentialClient struct { + ctrl *gomock.Controller + recorder *MockApplicationCredentialClientMockRecorder + isgomock struct{} +} + +// MockApplicationCredentialClientMockRecorder is the mock recorder for MockApplicationCredentialClient. +type MockApplicationCredentialClientMockRecorder struct { + mock *MockApplicationCredentialClient +} + +// NewMockApplicationCredentialClient creates a new mock instance. +func NewMockApplicationCredentialClient(ctrl *gomock.Controller) *MockApplicationCredentialClient { + mock := &MockApplicationCredentialClient{ctrl: ctrl} + mock.recorder = &MockApplicationCredentialClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockApplicationCredentialClient) EXPECT() *MockApplicationCredentialClientMockRecorder { + return m.recorder +} + +// CreateApplicationCredential mocks base method. +func (m *MockApplicationCredentialClient) CreateApplicationCredential(ctx context.Context, userID string, opts applicationcredentials.CreateOptsBuilder) (*applicationcredentials.ApplicationCredential, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateApplicationCredential", ctx, userID, opts) + ret0, _ := ret[0].(*applicationcredentials.ApplicationCredential) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateApplicationCredential indicates an expected call of CreateApplicationCredential. +func (mr *MockApplicationCredentialClientMockRecorder) CreateApplicationCredential(ctx, userID, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplicationCredential", reflect.TypeOf((*MockApplicationCredentialClient)(nil).CreateApplicationCredential), ctx, userID, opts) +} + +// DeleteApplicationCredential mocks base method. +func (m *MockApplicationCredentialClient) DeleteApplicationCredential(ctx context.Context, userID, resourceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteApplicationCredential", ctx, userID, resourceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteApplicationCredential indicates an expected call of DeleteApplicationCredential. +func (mr *MockApplicationCredentialClientMockRecorder) DeleteApplicationCredential(ctx, userID, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplicationCredential", reflect.TypeOf((*MockApplicationCredentialClient)(nil).DeleteApplicationCredential), ctx, userID, resourceID) +} + +// GetApplicationCredential mocks base method. +func (m *MockApplicationCredentialClient) GetApplicationCredential(ctx context.Context, resourceID string) (*applicationcredentials.ApplicationCredential, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetApplicationCredential", ctx, resourceID) + ret0, _ := ret[0].(*applicationcredentials.ApplicationCredential) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetApplicationCredential indicates an expected call of GetApplicationCredential. +func (mr *MockApplicationCredentialClientMockRecorder) GetApplicationCredential(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplicationCredential", reflect.TypeOf((*MockApplicationCredentialClient)(nil).GetApplicationCredential), ctx, resourceID) +} + +// ListApplicationCredentials mocks base method. +func (m *MockApplicationCredentialClient) ListApplicationCredentials(ctx context.Context, userID string, listOpts applicationcredentials.ListOptsBuilder) iter.Seq2[*applicationcredentials.ApplicationCredential, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListApplicationCredentials", ctx, userID, listOpts) + ret0, _ := ret[0].(iter.Seq2[*applicationcredentials.ApplicationCredential, error]) + return ret0 +} + +// ListApplicationCredentials indicates an expected call of ListApplicationCredentials. +func (mr *MockApplicationCredentialClientMockRecorder) ListApplicationCredentials(ctx, userID, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListApplicationCredentials", reflect.TypeOf((*MockApplicationCredentialClient)(nil).ListApplicationCredentials), ctx, userID, listOpts) +} diff --git a/internal/osclients/mock/compute.go b/internal/osclients/mock/compute.go index c22ab6984..1d73fbf72 100644 --- a/internal/osclients/mock/compute.go +++ b/internal/osclients/mock/compute.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -92,6 +92,21 @@ func (mr *MockComputeClientMockRecorder) CreateFlavor(ctx, opts any) *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFlavor", reflect.TypeOf((*MockComputeClient)(nil).CreateFlavor), ctx, opts) } +// CreateFlavorExtraSpecs mocks base method. +func (m *MockComputeClient) CreateFlavorExtraSpecs(ctx context.Context, id string, opts flavors.CreateExtraSpecsOptsBuilder) (map[string]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateFlavorExtraSpecs", ctx, id, opts) + ret0, _ := ret[0].(map[string]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateFlavorExtraSpecs indicates an expected call of CreateFlavorExtraSpecs. +func (mr *MockComputeClientMockRecorder) CreateFlavorExtraSpecs(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFlavorExtraSpecs", reflect.TypeOf((*MockComputeClient)(nil).CreateFlavorExtraSpecs), ctx, id, opts) +} + // CreateServer mocks base method. func (m *MockComputeClient) CreateServer(ctx context.Context, createOpts servers.CreateOptsBuilder, schedulerHints servers.SchedulerHintOptsBuilder) (*servers.Server, error) { m.ctrl.T.Helper() @@ -165,6 +180,20 @@ func (mr *MockComputeClientMockRecorder) DeleteFlavor(ctx, id any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFlavor", reflect.TypeOf((*MockComputeClient)(nil).DeleteFlavor), ctx, id) } +// DeleteFlavorExtraSpec mocks base method. +func (m *MockComputeClient) DeleteFlavorExtraSpec(ctx context.Context, id, key string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteFlavorExtraSpec", ctx, id, key) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteFlavorExtraSpec indicates an expected call of DeleteFlavorExtraSpec. +func (mr *MockComputeClientMockRecorder) DeleteFlavorExtraSpec(ctx, id, key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFlavorExtraSpec", reflect.TypeOf((*MockComputeClient)(nil).DeleteFlavorExtraSpec), ctx, id, key) +} + // DeleteServer mocks base method. func (m *MockComputeClient) DeleteServer(ctx context.Context, serverID string) error { m.ctrl.T.Helper() @@ -324,6 +353,21 @@ func (mr *MockComputeClientMockRecorder) ReplaceAllServerAttributesTags(ctx, res return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplaceAllServerAttributesTags", reflect.TypeOf((*MockComputeClient)(nil).ReplaceAllServerAttributesTags), ctx, resourceID, opts) } +// ReplaceServerMetadata mocks base method. +func (m *MockComputeClient) ReplaceServerMetadata(ctx context.Context, serverID string, opts servers.MetadataOpts) (map[string]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReplaceServerMetadata", ctx, serverID, opts) + ret0, _ := ret[0].(map[string]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReplaceServerMetadata indicates an expected call of ReplaceServerMetadata. +func (mr *MockComputeClientMockRecorder) ReplaceServerMetadata(ctx, serverID, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplaceServerMetadata", reflect.TypeOf((*MockComputeClient)(nil).ReplaceServerMetadata), ctx, serverID, opts) +} + // UpdateServer mocks base method. func (m *MockComputeClient) UpdateServer(ctx context.Context, id string, opts servers.UpdateOptsBuilder) (*servers.Server, error) { m.ctrl.T.Helper() diff --git a/internal/osclients/mock/doc.go b/internal/osclients/mock/doc.go index 47292b65f..466a548e6 100644 --- a/internal/osclients/mock/doc.go +++ b/internal/osclients/mock/doc.go @@ -1,6 +1,6 @@ // Code generated by resource-generator. DO NOT EDIT. /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,9 +35,18 @@ import ( //go:generate mockgen -package mock -destination=identity.go -source=../identity.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock IdentityClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt identity.go > _identity.go && mv _identity.go identity.go" +//go:generate mockgen -package mock -destination=addressscope.go -source=../addressscope.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock AddressScopeClient +//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt addressscope.go > _addressscope.go && mv _addressscope.go addressscope.go" + +//go:generate mockgen -package mock -destination=applicationcredential.go -source=../applicationcredential.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock ApplicationCredentialClient +//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt applicationcredential.go > _applicationcredential.go && mv _applicationcredential.go applicationcredential.go" + //go:generate mockgen -package mock -destination=domain.go -source=../domain.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock DomainClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt domain.go > _domain.go && mv _domain.go domain.go" +//go:generate mockgen -package mock -destination=endpoint.go -source=../endpoint.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock EndpointClient +//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt endpoint.go > _endpoint.go && mv _endpoint.go endpoint.go" + //go:generate mockgen -package mock -destination=group.go -source=../group.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock GroupClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt group.go > _group.go && mv _group.go group.go" @@ -47,9 +56,18 @@ import ( //go:generate mockgen -package mock -destination=role.go -source=../role.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock RoleClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt role.go > _role.go && mv _role.go role.go" +//go:generate mockgen -package mock -destination=roleassignment.go -source=../roleassignment.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock RoleAssignmentClient +//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt roleassignment.go > _roleassignment.go && mv _roleassignment.go roleassignment.go" + //go:generate mockgen -package mock -destination=service.go -source=../service.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock ServiceClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt service.go > _service.go && mv _service.go service.go" +//go:generate mockgen -package mock -destination=sharenetwork.go -source=../sharenetwork.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock ShareNetworkClient +//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt sharenetwork.go > _sharenetwork.go && mv _sharenetwork.go sharenetwork.go" + +//go:generate mockgen -package mock -destination=user.go -source=../user.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock UserClient +//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt user.go > _user.go && mv _user.go user.go" + //go:generate mockgen -package mock -destination=volume.go -source=../volume.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock VolumeClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt volume.go > _volume.go && mv _volume.go volume.go" diff --git a/internal/osclients/mock/domain.go b/internal/osclients/mock/domain.go index bfc9c6c1c..a16b2b178 100644 --- a/internal/osclients/mock/domain.go +++ b/internal/osclients/mock/domain.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/endpoint.go b/internal/osclients/mock/endpoint.go new file mode 100644 index 000000000..ed4ea1be4 --- /dev/null +++ b/internal/osclients/mock/endpoint.go @@ -0,0 +1,131 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../endpoint.go +// +// Generated by this command: +// +// mockgen -package mock -destination=endpoint.go -source=../endpoint.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock EndpointClient +// + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + iter "iter" + reflect "reflect" + + endpoints "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/endpoints" + gomock "go.uber.org/mock/gomock" +) + +// MockEndpointClient is a mock of EndpointClient interface. +type MockEndpointClient struct { + ctrl *gomock.Controller + recorder *MockEndpointClientMockRecorder + isgomock struct{} +} + +// MockEndpointClientMockRecorder is the mock recorder for MockEndpointClient. +type MockEndpointClientMockRecorder struct { + mock *MockEndpointClient +} + +// NewMockEndpointClient creates a new mock instance. +func NewMockEndpointClient(ctrl *gomock.Controller) *MockEndpointClient { + mock := &MockEndpointClient{ctrl: ctrl} + mock.recorder = &MockEndpointClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEndpointClient) EXPECT() *MockEndpointClientMockRecorder { + return m.recorder +} + +// CreateEndpoint mocks base method. +func (m *MockEndpointClient) CreateEndpoint(ctx context.Context, opts endpoints.CreateOptsBuilder) (*endpoints.Endpoint, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateEndpoint", ctx, opts) + ret0, _ := ret[0].(*endpoints.Endpoint) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateEndpoint indicates an expected call of CreateEndpoint. +func (mr *MockEndpointClientMockRecorder) CreateEndpoint(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEndpoint", reflect.TypeOf((*MockEndpointClient)(nil).CreateEndpoint), ctx, opts) +} + +// DeleteEndpoint mocks base method. +func (m *MockEndpointClient) DeleteEndpoint(ctx context.Context, resourceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteEndpoint", ctx, resourceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteEndpoint indicates an expected call of DeleteEndpoint. +func (mr *MockEndpointClientMockRecorder) DeleteEndpoint(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEndpoint", reflect.TypeOf((*MockEndpointClient)(nil).DeleteEndpoint), ctx, resourceID) +} + +// GetEndpoint mocks base method. +func (m *MockEndpointClient) GetEndpoint(ctx context.Context, resourceID string) (*endpoints.Endpoint, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEndpoint", ctx, resourceID) + ret0, _ := ret[0].(*endpoints.Endpoint) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetEndpoint indicates an expected call of GetEndpoint. +func (mr *MockEndpointClientMockRecorder) GetEndpoint(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEndpoint", reflect.TypeOf((*MockEndpointClient)(nil).GetEndpoint), ctx, resourceID) +} + +// ListEndpoints mocks base method. +func (m *MockEndpointClient) ListEndpoints(ctx context.Context, listOpts endpoints.ListOptsBuilder) iter.Seq2[*endpoints.Endpoint, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListEndpoints", ctx, listOpts) + ret0, _ := ret[0].(iter.Seq2[*endpoints.Endpoint, error]) + return ret0 +} + +// ListEndpoints indicates an expected call of ListEndpoints. +func (mr *MockEndpointClientMockRecorder) ListEndpoints(ctx, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEndpoints", reflect.TypeOf((*MockEndpointClient)(nil).ListEndpoints), ctx, listOpts) +} + +// UpdateEndpoint mocks base method. +func (m *MockEndpointClient) UpdateEndpoint(ctx context.Context, id string, opts endpoints.UpdateOptsBuilder) (*endpoints.Endpoint, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateEndpoint", ctx, id, opts) + ret0, _ := ret[0].(*endpoints.Endpoint) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateEndpoint indicates an expected call of UpdateEndpoint. +func (mr *MockEndpointClientMockRecorder) UpdateEndpoint(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateEndpoint", reflect.TypeOf((*MockEndpointClient)(nil).UpdateEndpoint), ctx, id, opts) +} diff --git a/internal/osclients/mock/group.go b/internal/osclients/mock/group.go index f4c5da425..0612ebed2 100644 --- a/internal/osclients/mock/group.go +++ b/internal/osclients/mock/group.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/identity.go b/internal/osclients/mock/identity.go index 70079f962..17f8e4f6c 100644 --- a/internal/osclients/mock/identity.go +++ b/internal/osclients/mock/identity.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/image.go b/internal/osclients/mock/image.go index dc5dba62e..939917569 100644 --- a/internal/osclients/mock/image.go +++ b/internal/osclients/mock/image.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/keypair.go b/internal/osclients/mock/keypair.go index e4dfac055..f5d28c603 100644 --- a/internal/osclients/mock/keypair.go +++ b/internal/osclients/mock/keypair.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/networking.go b/internal/osclients/mock/networking.go index 9b5e25046..deaa04f70 100644 --- a/internal/osclients/mock/networking.go +++ b/internal/osclients/mock/networking.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import ( routers "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers" groups "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups" rules "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules" + trunks "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks" networks "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/networks" ports "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports" subnets "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets" @@ -80,6 +81,21 @@ func (mr *MockNetworkClientMockRecorder) AddRouterInterface(ctx, id, opts any) * return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRouterInterface", reflect.TypeOf((*MockNetworkClient)(nil).AddRouterInterface), ctx, id, opts) } +// AddSubports mocks base method. +func (m *MockNetworkClient) AddSubports(ctx context.Context, id string, opts trunks.AddSubportsOptsBuilder) (*trunks.Trunk, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddSubports", ctx, id, opts) + ret0, _ := ret[0].(*trunks.Trunk) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AddSubports indicates an expected call of AddSubports. +func (mr *MockNetworkClientMockRecorder) AddSubports(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSubports", reflect.TypeOf((*MockNetworkClient)(nil).AddSubports), ctx, id, opts) +} + // CreateFloatingIP mocks base method. func (m *MockNetworkClient) CreateFloatingIP(ctx context.Context, opts floatingips.CreateOptsBuilder) (*floatingips.FloatingIP, error) { m.ctrl.T.Helper() @@ -185,6 +201,21 @@ func (mr *MockNetworkClientMockRecorder) CreateSubnet(ctx, opts any) *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSubnet", reflect.TypeOf((*MockNetworkClient)(nil).CreateSubnet), ctx, opts) } +// CreateTrunk mocks base method. +func (m *MockNetworkClient) CreateTrunk(ctx context.Context, opts trunks.CreateOptsBuilder) (*trunks.Trunk, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateTrunk", ctx, opts) + ret0, _ := ret[0].(*trunks.Trunk) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateTrunk indicates an expected call of CreateTrunk. +func (mr *MockNetworkClientMockRecorder) CreateTrunk(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTrunk", reflect.TypeOf((*MockNetworkClient)(nil).CreateTrunk), ctx, opts) +} + // DeleteFloatingIP mocks base method. func (m *MockNetworkClient) DeleteFloatingIP(ctx context.Context, id string) error { m.ctrl.T.Helper() @@ -283,6 +314,20 @@ func (mr *MockNetworkClientMockRecorder) DeleteSubnet(ctx, id any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSubnet", reflect.TypeOf((*MockNetworkClient)(nil).DeleteSubnet), ctx, id) } +// DeleteTrunk mocks base method. +func (m *MockNetworkClient) DeleteTrunk(ctx context.Context, resourceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteTrunk", ctx, resourceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteTrunk indicates an expected call of DeleteTrunk. +func (mr *MockNetworkClientMockRecorder) DeleteTrunk(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTrunk", reflect.TypeOf((*MockNetworkClient)(nil).DeleteTrunk), ctx, resourceID) +} + // GetFloatingIP mocks base method. func (m *MockNetworkClient) GetFloatingIP(ctx context.Context, id string) (*floatingips.FloatingIP, error) { m.ctrl.T.Helper() @@ -388,6 +433,21 @@ func (mr *MockNetworkClientMockRecorder) GetSubnet(ctx, id any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnet", reflect.TypeOf((*MockNetworkClient)(nil).GetSubnet), ctx, id) } +// GetTrunk mocks base method. +func (m *MockNetworkClient) GetTrunk(ctx context.Context, resourceID string) (*trunks.Trunk, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTrunk", ctx, resourceID) + ret0, _ := ret[0].(*trunks.Trunk) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTrunk indicates an expected call of GetTrunk. +func (mr *MockNetworkClientMockRecorder) GetTrunk(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTrunk", reflect.TypeOf((*MockNetworkClient)(nil).GetTrunk), ctx, resourceID) +} + // ListFloatingIP mocks base method. func (m *MockNetworkClient) ListFloatingIP(ctx context.Context, opts floatingips.ListOptsBuilder) iter.Seq2[*floatingips.FloatingIP, error] { m.ctrl.T.Helper() @@ -487,6 +547,20 @@ func (mr *MockNetworkClientMockRecorder) ListSubnet(ctx, opts any) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSubnet", reflect.TypeOf((*MockNetworkClient)(nil).ListSubnet), ctx, opts) } +// ListTrunks mocks base method. +func (m *MockNetworkClient) ListTrunks(ctx context.Context, listOpts trunks.ListOptsBuilder) iter.Seq2[*trunks.Trunk, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListTrunks", ctx, listOpts) + ret0, _ := ret[0].(iter.Seq2[*trunks.Trunk, error]) + return ret0 +} + +// ListTrunks indicates an expected call of ListTrunks. +func (mr *MockNetworkClientMockRecorder) ListTrunks(ctx, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTrunks", reflect.TypeOf((*MockNetworkClient)(nil).ListTrunks), ctx, listOpts) +} + // RemoveRouterInterface mocks base method. func (m *MockNetworkClient) RemoveRouterInterface(ctx context.Context, id string, opts routers.RemoveInterfaceOptsBuilder) (*routers.InterfaceInfo, error) { m.ctrl.T.Helper() @@ -502,6 +576,20 @@ func (mr *MockNetworkClientMockRecorder) RemoveRouterInterface(ctx, id, opts any return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveRouterInterface", reflect.TypeOf((*MockNetworkClient)(nil).RemoveRouterInterface), ctx, id, opts) } +// RemoveSubports mocks base method. +func (m *MockNetworkClient) RemoveSubports(ctx context.Context, id string, opts trunks.RemoveSubportsOpts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveSubports", ctx, id, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveSubports indicates an expected call of RemoveSubports. +func (mr *MockNetworkClientMockRecorder) RemoveSubports(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSubports", reflect.TypeOf((*MockNetworkClient)(nil).RemoveSubports), ctx, id, opts) +} + // ReplaceAllAttributesTags mocks base method. func (m *MockNetworkClient) ReplaceAllAttributesTags(ctx context.Context, resourceType, resourceID string, opts attributestags.ReplaceAllOptsBuilder) ([]string, error) { m.ctrl.T.Helper() @@ -606,3 +694,18 @@ func (mr *MockNetworkClientMockRecorder) UpdateSubnet(ctx, id, opts any) *gomock mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSubnet", reflect.TypeOf((*MockNetworkClient)(nil).UpdateSubnet), ctx, id, opts) } + +// UpdateTrunk mocks base method. +func (m *MockNetworkClient) UpdateTrunk(ctx context.Context, id string, opts trunks.UpdateOptsBuilder) (*trunks.Trunk, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTrunk", ctx, id, opts) + ret0, _ := ret[0].(*trunks.Trunk) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateTrunk indicates an expected call of UpdateTrunk. +func (mr *MockNetworkClientMockRecorder) UpdateTrunk(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTrunk", reflect.TypeOf((*MockNetworkClient)(nil).UpdateTrunk), ctx, id, opts) +} diff --git a/internal/osclients/mock/role.go b/internal/osclients/mock/role.go index 3108304d2..08ea8397c 100644 --- a/internal/osclients/mock/role.go +++ b/internal/osclients/mock/role.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/roleassignment.go b/internal/osclients/mock/roleassignment.go new file mode 100644 index 000000000..fa513aba8 --- /dev/null +++ b/internal/osclients/mock/roleassignment.go @@ -0,0 +1,100 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../roleassignment.go +// +// Generated by this command: +// +// mockgen -package mock -destination=roleassignment.go -source=../roleassignment.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock RoleAssignmentClient +// + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + iter "iter" + reflect "reflect" + + roles "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/roles" + gomock "go.uber.org/mock/gomock" +) + +// MockRoleAssignmentClient is a mock of RoleAssignmentClient interface. +type MockRoleAssignmentClient struct { + ctrl *gomock.Controller + recorder *MockRoleAssignmentClientMockRecorder + isgomock struct{} +} + +// MockRoleAssignmentClientMockRecorder is the mock recorder for MockRoleAssignmentClient. +type MockRoleAssignmentClientMockRecorder struct { + mock *MockRoleAssignmentClient +} + +// NewMockRoleAssignmentClient creates a new mock instance. +func NewMockRoleAssignmentClient(ctrl *gomock.Controller) *MockRoleAssignmentClient { + mock := &MockRoleAssignmentClient{ctrl: ctrl} + mock.recorder = &MockRoleAssignmentClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRoleAssignmentClient) EXPECT() *MockRoleAssignmentClientMockRecorder { + return m.recorder +} + +// AssignRole mocks base method. +func (m *MockRoleAssignmentClient) AssignRole(ctx context.Context, roleID string, opts roles.AssignOpts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssignRole", ctx, roleID, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// AssignRole indicates an expected call of AssignRole. +func (mr *MockRoleAssignmentClientMockRecorder) AssignRole(ctx, roleID, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssignRole", reflect.TypeOf((*MockRoleAssignmentClient)(nil).AssignRole), ctx, roleID, opts) +} + +// ListRoleAssignments mocks base method. +func (m *MockRoleAssignmentClient) ListRoleAssignments(ctx context.Context, listOpts roles.ListAssignmentsOpts) iter.Seq2[*roles.RoleAssignment, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListRoleAssignments", ctx, listOpts) + ret0, _ := ret[0].(iter.Seq2[*roles.RoleAssignment, error]) + return ret0 +} + +// ListRoleAssignments indicates an expected call of ListRoleAssignments. +func (mr *MockRoleAssignmentClientMockRecorder) ListRoleAssignments(ctx, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRoleAssignments", reflect.TypeOf((*MockRoleAssignmentClient)(nil).ListRoleAssignments), ctx, listOpts) +} + +// UnassignRole mocks base method. +func (m *MockRoleAssignmentClient) UnassignRole(ctx context.Context, roleID string, opts roles.UnassignOpts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnassignRole", ctx, roleID, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// UnassignRole indicates an expected call of UnassignRole. +func (mr *MockRoleAssignmentClientMockRecorder) UnassignRole(ctx, roleID, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnassignRole", reflect.TypeOf((*MockRoleAssignmentClient)(nil).UnassignRole), ctx, roleID, opts) +} diff --git a/internal/osclients/mock/service.go b/internal/osclients/mock/service.go index b8c9191a8..05bee911b 100644 --- a/internal/osclients/mock/service.go +++ b/internal/osclients/mock/service.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/sharenetwork.go b/internal/osclients/mock/sharenetwork.go new file mode 100644 index 000000000..e492bf9d7 --- /dev/null +++ b/internal/osclients/mock/sharenetwork.go @@ -0,0 +1,131 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../sharenetwork.go +// +// Generated by this command: +// +// mockgen -package mock -destination=sharenetwork.go -source=../sharenetwork.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock ShareNetworkClient +// + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + iter "iter" + reflect "reflect" + + sharenetworks "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharenetworks" + gomock "go.uber.org/mock/gomock" +) + +// MockShareNetworkClient is a mock of ShareNetworkClient interface. +type MockShareNetworkClient struct { + ctrl *gomock.Controller + recorder *MockShareNetworkClientMockRecorder + isgomock struct{} +} + +// MockShareNetworkClientMockRecorder is the mock recorder for MockShareNetworkClient. +type MockShareNetworkClientMockRecorder struct { + mock *MockShareNetworkClient +} + +// NewMockShareNetworkClient creates a new mock instance. +func NewMockShareNetworkClient(ctrl *gomock.Controller) *MockShareNetworkClient { + mock := &MockShareNetworkClient{ctrl: ctrl} + mock.recorder = &MockShareNetworkClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockShareNetworkClient) EXPECT() *MockShareNetworkClientMockRecorder { + return m.recorder +} + +// CreateShareNetwork mocks base method. +func (m *MockShareNetworkClient) CreateShareNetwork(ctx context.Context, opts sharenetworks.CreateOptsBuilder) (*sharenetworks.ShareNetwork, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateShareNetwork", ctx, opts) + ret0, _ := ret[0].(*sharenetworks.ShareNetwork) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateShareNetwork indicates an expected call of CreateShareNetwork. +func (mr *MockShareNetworkClientMockRecorder) CreateShareNetwork(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateShareNetwork", reflect.TypeOf((*MockShareNetworkClient)(nil).CreateShareNetwork), ctx, opts) +} + +// DeleteShareNetwork mocks base method. +func (m *MockShareNetworkClient) DeleteShareNetwork(ctx context.Context, resourceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteShareNetwork", ctx, resourceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteShareNetwork indicates an expected call of DeleteShareNetwork. +func (mr *MockShareNetworkClientMockRecorder) DeleteShareNetwork(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteShareNetwork", reflect.TypeOf((*MockShareNetworkClient)(nil).DeleteShareNetwork), ctx, resourceID) +} + +// GetShareNetwork mocks base method. +func (m *MockShareNetworkClient) GetShareNetwork(ctx context.Context, resourceID string) (*sharenetworks.ShareNetwork, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetShareNetwork", ctx, resourceID) + ret0, _ := ret[0].(*sharenetworks.ShareNetwork) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetShareNetwork indicates an expected call of GetShareNetwork. +func (mr *MockShareNetworkClientMockRecorder) GetShareNetwork(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetShareNetwork", reflect.TypeOf((*MockShareNetworkClient)(nil).GetShareNetwork), ctx, resourceID) +} + +// ListShareNetworks mocks base method. +func (m *MockShareNetworkClient) ListShareNetworks(ctx context.Context, listOpts sharenetworks.ListOptsBuilder) iter.Seq2[*sharenetworks.ShareNetwork, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListShareNetworks", ctx, listOpts) + ret0, _ := ret[0].(iter.Seq2[*sharenetworks.ShareNetwork, error]) + return ret0 +} + +// ListShareNetworks indicates an expected call of ListShareNetworks. +func (mr *MockShareNetworkClientMockRecorder) ListShareNetworks(ctx, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListShareNetworks", reflect.TypeOf((*MockShareNetworkClient)(nil).ListShareNetworks), ctx, listOpts) +} + +// UpdateShareNetwork mocks base method. +func (m *MockShareNetworkClient) UpdateShareNetwork(ctx context.Context, id string, opts sharenetworks.UpdateOptsBuilder) (*sharenetworks.ShareNetwork, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateShareNetwork", ctx, id, opts) + ret0, _ := ret[0].(*sharenetworks.ShareNetwork) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateShareNetwork indicates an expected call of UpdateShareNetwork. +func (mr *MockShareNetworkClientMockRecorder) UpdateShareNetwork(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateShareNetwork", reflect.TypeOf((*MockShareNetworkClient)(nil).UpdateShareNetwork), ctx, id, opts) +} diff --git a/internal/osclients/mock/user.go b/internal/osclients/mock/user.go new file mode 100644 index 000000000..7ce0e5cd1 --- /dev/null +++ b/internal/osclients/mock/user.go @@ -0,0 +1,131 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../user.go +// +// Generated by this command: +// +// mockgen -package mock -destination=user.go -source=../user.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock UserClient +// + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + iter "iter" + reflect "reflect" + + users "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/users" + gomock "go.uber.org/mock/gomock" +) + +// MockUserClient is a mock of UserClient interface. +type MockUserClient struct { + ctrl *gomock.Controller + recorder *MockUserClientMockRecorder + isgomock struct{} +} + +// MockUserClientMockRecorder is the mock recorder for MockUserClient. +type MockUserClientMockRecorder struct { + mock *MockUserClient +} + +// NewMockUserClient creates a new mock instance. +func NewMockUserClient(ctrl *gomock.Controller) *MockUserClient { + mock := &MockUserClient{ctrl: ctrl} + mock.recorder = &MockUserClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockUserClient) EXPECT() *MockUserClientMockRecorder { + return m.recorder +} + +// CreateUser mocks base method. +func (m *MockUserClient) CreateUser(ctx context.Context, opts users.CreateOptsBuilder) (*users.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateUser", ctx, opts) + ret0, _ := ret[0].(*users.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateUser indicates an expected call of CreateUser. +func (mr *MockUserClientMockRecorder) CreateUser(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockUserClient)(nil).CreateUser), ctx, opts) +} + +// DeleteUser mocks base method. +func (m *MockUserClient) DeleteUser(ctx context.Context, resourceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteUser", ctx, resourceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteUser indicates an expected call of DeleteUser. +func (mr *MockUserClientMockRecorder) DeleteUser(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUser", reflect.TypeOf((*MockUserClient)(nil).DeleteUser), ctx, resourceID) +} + +// GetUser mocks base method. +func (m *MockUserClient) GetUser(ctx context.Context, resourceID string) (*users.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUser", ctx, resourceID) + ret0, _ := ret[0].(*users.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUser indicates an expected call of GetUser. +func (mr *MockUserClientMockRecorder) GetUser(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUser", reflect.TypeOf((*MockUserClient)(nil).GetUser), ctx, resourceID) +} + +// ListUsers mocks base method. +func (m *MockUserClient) ListUsers(ctx context.Context, listOpts users.ListOptsBuilder) iter.Seq2[*users.User, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListUsers", ctx, listOpts) + ret0, _ := ret[0].(iter.Seq2[*users.User, error]) + return ret0 +} + +// ListUsers indicates an expected call of ListUsers. +func (mr *MockUserClientMockRecorder) ListUsers(ctx, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUsers", reflect.TypeOf((*MockUserClient)(nil).ListUsers), ctx, listOpts) +} + +// UpdateUser mocks base method. +func (m *MockUserClient) UpdateUser(ctx context.Context, id string, opts users.UpdateOptsBuilder) (*users.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUser", ctx, id, opts) + ret0, _ := ret[0].(*users.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUser indicates an expected call of UpdateUser. +func (mr *MockUserClientMockRecorder) UpdateUser(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockUserClient)(nil).UpdateUser), ctx, id, opts) +} diff --git a/internal/osclients/mock/volume.go b/internal/osclients/mock/volume.go index efb1390f0..ca736d3d1 100644 --- a/internal/osclients/mock/volume.go +++ b/internal/osclients/mock/volume.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/mock/volumetype.go b/internal/osclients/mock/volumetype.go index e0dd5be49..08a648872 100644 --- a/internal/osclients/mock/volumetype.go +++ b/internal/osclients/mock/volumetype.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/internal/osclients/networking.go b/internal/osclients/networking.go index 99156d64e..a628d9146 100644 --- a/internal/osclients/networking.go +++ b/internal/osclients/networking.go @@ -18,6 +18,7 @@ package osclients import ( "context" + "encoding/json" "fmt" "iter" @@ -32,6 +33,7 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/mtu" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsbinding" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsecurity" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portstrustedvif" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/provider" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules" @@ -56,6 +58,42 @@ type PortExt struct { ports.Port portsecurity.PortSecurityExt portsbinding.PortsBindingExt + portstrustedvif.PortTrustedVIFExt + + // PropagateUplinkStatusPtr is a pointer variant of ports.Port.PropagateUplinkStatus. + // The embedded field is a non-pointer bool that defaults to false, making it + // impossible to distinguish "extension not enabled" from "explicitly false". + // This pointer allows detecting whether the field was present in the API response. + // It won't be needed with Gophercloud v3. + PropagateUplinkStatusPtr *bool `json:"propagate_uplink_status,omitempty"` +} + +// TODO(winiciusallan): Drop this custom unmarshaler once Gophercloud is +// on V3, so we have the following change +// https://github.com/gophercloud/gophercloud/pull/3609. +func (p *PortExt) UnmarshalJSON(b []byte) error { + if err := json.Unmarshal(b, &p.Port); err != nil { + return err + } + if err := json.Unmarshal(b, &p.PortSecurityExt); err != nil { + return err + } + if err := json.Unmarshal(b, &p.PortsBindingExt); err != nil { + return err + } + if err := json.Unmarshal(b, &p.PortTrustedVIFExt); err != nil { + return err + } + + var tmp struct { + PropagateUplinkStatusPtr *bool `json:"propagate_uplink_status"` + } + if err := json.Unmarshal(b, &tmp); err != nil { + return err + } + + p.PropagateUplinkStatusPtr = tmp.PropagateUplinkStatusPtr + return nil } type NetworkClient interface { @@ -102,6 +140,14 @@ type NetworkClient interface { GetSubnet(ctx context.Context, id string) (*subnets.Subnet, error) UpdateSubnet(ctx context.Context, id string, opts subnets.UpdateOptsBuilder) (*subnets.Subnet, error) + ListTrunks(ctx context.Context, listOpts trunks.ListOptsBuilder) iter.Seq2[*trunks.Trunk, error] + CreateTrunk(ctx context.Context, opts trunks.CreateOptsBuilder) (*trunks.Trunk, error) + DeleteTrunk(ctx context.Context, resourceID string) error + GetTrunk(ctx context.Context, resourceID string) (*trunks.Trunk, error) + UpdateTrunk(ctx context.Context, id string, opts trunks.UpdateOptsBuilder) (*trunks.Trunk, error) + AddSubports(ctx context.Context, id string, opts trunks.AddSubportsOptsBuilder) (*trunks.Trunk, error) + RemoveSubports(ctx context.Context, id string, opts trunks.RemoveSubportsOpts) error + ReplaceAllAttributesTags(ctx context.Context, resourceType string, resourceID string, opts attributestags.ReplaceAllOptsBuilder) ([]string, error) } @@ -179,6 +225,7 @@ func (c networkClient) ListPort(ctx context.Context, opts ports.ListOptsBuilder) } return resources, nil } + pager := ports.List(c.serviceClient, opts) return func(yield func(*PortExt, error) bool) { _ = pager.EachPage(ctx, yieldPage(extractPortExt, yield)) @@ -214,31 +261,6 @@ func (c networkClient) UpdatePort(ctx context.Context, id string, opts ports.Upd return &portExt, nil } -func (c networkClient) CreateTrunk(ctx context.Context, opts trunks.CreateOptsBuilder) (*trunks.Trunk, error) { - return trunks.Create(ctx, c.serviceClient, opts).Extract() -} - -func (c networkClient) DeleteTrunk(ctx context.Context, id string) error { - return trunks.Delete(ctx, c.serviceClient, id).ExtractErr() -} - -func (c networkClient) ListTrunkSubports(ctx context.Context, trunkID string) ([]trunks.Subport, error) { - return trunks.GetSubports(ctx, c.serviceClient, trunkID).Extract() -} - -func (c networkClient) RemoveSubports(ctx context.Context, id string, opts trunks.RemoveSubportsOpts) error { - _, err := trunks.RemoveSubports(ctx, c.serviceClient, id, opts).Extract() - return err -} - -func (c networkClient) ListTrunk(ctx context.Context, opts trunks.ListOptsBuilder) ([]trunks.Trunk, error) { - allPages, err := trunks.List(c.serviceClient, opts).AllPages(ctx) - if err != nil { - return nil, err - } - return trunks.ExtractTrunks(allPages) -} - func (c networkClient) CreateRouter(ctx context.Context, opts routers.CreateOptsBuilder) (*routers.Router, error) { return routers.Create(ctx, c.serviceClient, opts).Extract() } @@ -372,3 +394,35 @@ func (c networkClient) ListExtensions(ctx context.Context) ([]extensions.Extensi } return extensions.ExtractExtensions(allPages) } + +func (c networkClient) ListTrunks(ctx context.Context, listOpts trunks.ListOptsBuilder) iter.Seq2[*trunks.Trunk, error] { + pager := trunks.List(c.serviceClient, listOpts) + return func(yield func(*trunks.Trunk, error) bool) { + _ = pager.EachPage(ctx, yieldPage(trunks.ExtractTrunks, yield)) + } +} + +func (c networkClient) CreateTrunk(ctx context.Context, opts trunks.CreateOptsBuilder) (*trunks.Trunk, error) { + return trunks.Create(ctx, c.serviceClient, opts).Extract() +} + +func (c networkClient) DeleteTrunk(ctx context.Context, resourceID string) error { + return trunks.Delete(ctx, c.serviceClient, resourceID).ExtractErr() +} + +func (c networkClient) GetTrunk(ctx context.Context, resourceID string) (*trunks.Trunk, error) { + return trunks.Get(ctx, c.serviceClient, resourceID).Extract() +} + +func (c networkClient) UpdateTrunk(ctx context.Context, id string, opts trunks.UpdateOptsBuilder) (*trunks.Trunk, error) { + return trunks.Update(ctx, c.serviceClient, id, opts).Extract() +} + +func (c networkClient) AddSubports(ctx context.Context, id string, opts trunks.AddSubportsOptsBuilder) (*trunks.Trunk, error) { + return trunks.AddSubports(ctx, c.serviceClient, id, opts).Extract() +} + +func (c networkClient) RemoveSubports(ctx context.Context, id string, opts trunks.RemoveSubportsOpts) error { + _, err := trunks.RemoveSubports(ctx, c.serviceClient, id, opts).Extract() + return err +} diff --git a/internal/osclients/roleassignment.go b/internal/osclients/roleassignment.go new file mode 100644 index 000000000..bf83a75b2 --- /dev/null +++ b/internal/osclients/roleassignment.go @@ -0,0 +1,86 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osclients + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/roles" + "github.com/gophercloud/utils/v2/openstack/clientconfig" +) + +type RoleAssignmentClient interface { + ListRoleAssignments(ctx context.Context, listOpts roles.ListAssignmentsOpts) iter.Seq2[*roles.RoleAssignment, error] + AssignRole(ctx context.Context, roleID string, opts roles.AssignOpts) error + UnassignRole(ctx context.Context, roleID string, opts roles.UnassignOpts) error +} + +type roleassignmentClient struct{ client *gophercloud.ServiceClient } + +// NewRoleAssignmentClient returns a new OpenStack Identity client for role assignments. +func NewRoleAssignmentClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (RoleAssignmentClient, error) { + client, err := openstack.NewIdentityV3(providerClient, gophercloud.EndpointOpts{ + Region: providerClientOpts.RegionName, + Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType), + }) + + if err != nil { + return nil, fmt.Errorf("failed to create role assignment service client: %v", err) + } + + return &roleassignmentClient{client}, nil +} + +func (c roleassignmentClient) ListRoleAssignments(ctx context.Context, listOpts roles.ListAssignmentsOpts) iter.Seq2[*roles.RoleAssignment, error] { + pager := roles.ListAssignments(c.client, listOpts) + return func(yield func(*roles.RoleAssignment, error) bool) { + _ = pager.EachPage(ctx, yieldPage(roles.ExtractRoleAssignments, yield)) + } +} + +func (c roleassignmentClient) AssignRole(ctx context.Context, roleID string, opts roles.AssignOpts) error { + return roles.Assign(ctx, c.client, roleID, opts).ExtractErr() +} + +func (c roleassignmentClient) UnassignRole(ctx context.Context, roleID string, opts roles.UnassignOpts) error { + return roles.Unassign(ctx, c.client, roleID, opts).ExtractErr() +} + +type roleassignmentErrorClient struct{ error } + +// NewRoleAssignmentErrorClient returns a RoleAssignmentClient in which every method returns the given error. +func NewRoleAssignmentErrorClient(e error) RoleAssignmentClient { + return roleassignmentErrorClient{e} +} + +func (e roleassignmentErrorClient) ListRoleAssignments(_ context.Context, _ roles.ListAssignmentsOpts) iter.Seq2[*roles.RoleAssignment, error] { + return func(yield func(*roles.RoleAssignment, error) bool) { + yield(nil, e.error) + } +} + +func (e roleassignmentErrorClient) AssignRole(_ context.Context, _ string, _ roles.AssignOpts) error { + return e.error +} + +func (e roleassignmentErrorClient) UnassignRole(_ context.Context, _ string, _ roles.UnassignOpts) error { + return e.error +} diff --git a/internal/osclients/sharenetwork.go b/internal/osclients/sharenetwork.go new file mode 100644 index 000000000..a8382eac1 --- /dev/null +++ b/internal/osclients/sharenetwork.go @@ -0,0 +1,104 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osclients + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack" + "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharenetworks" + "github.com/gophercloud/utils/v2/openstack/clientconfig" +) + +type ShareNetworkClient interface { + ListShareNetworks(ctx context.Context, listOpts sharenetworks.ListOptsBuilder) iter.Seq2[*sharenetworks.ShareNetwork, error] + CreateShareNetwork(ctx context.Context, opts sharenetworks.CreateOptsBuilder) (*sharenetworks.ShareNetwork, error) + DeleteShareNetwork(ctx context.Context, resourceID string) error + GetShareNetwork(ctx context.Context, resourceID string) (*sharenetworks.ShareNetwork, error) + UpdateShareNetwork(ctx context.Context, id string, opts sharenetworks.UpdateOptsBuilder) (*sharenetworks.ShareNetwork, error) +} + +type sharenetworkClient struct{ client *gophercloud.ServiceClient } + +// NewShareNetworkClient returns a new OpenStack client. +func NewShareNetworkClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (ShareNetworkClient, error) { + client, err := openstack.NewSharedFileSystemV2(providerClient, gophercloud.EndpointOpts{ + Region: providerClientOpts.RegionName, + Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType), + }) + + if err != nil { + return nil, fmt.Errorf("failed to create sharenetwork service client: %v", err) + } + + return &sharenetworkClient{client}, nil +} + +func (c sharenetworkClient) ListShareNetworks(ctx context.Context, listOpts sharenetworks.ListOptsBuilder) iter.Seq2[*sharenetworks.ShareNetwork, error] { + pager := sharenetworks.ListDetail(c.client, listOpts) + return func(yield func(*sharenetworks.ShareNetwork, error) bool) { + _ = pager.EachPage(ctx, yieldPage(sharenetworks.ExtractShareNetworks, yield)) + } +} + +func (c sharenetworkClient) CreateShareNetwork(ctx context.Context, opts sharenetworks.CreateOptsBuilder) (*sharenetworks.ShareNetwork, error) { + return sharenetworks.Create(ctx, c.client, opts).Extract() +} + +func (c sharenetworkClient) DeleteShareNetwork(ctx context.Context, resourceID string) error { + return sharenetworks.Delete(ctx, c.client, resourceID).ExtractErr() +} + +func (c sharenetworkClient) GetShareNetwork(ctx context.Context, resourceID string) (*sharenetworks.ShareNetwork, error) { + return sharenetworks.Get(ctx, c.client, resourceID).Extract() +} + +func (c sharenetworkClient) UpdateShareNetwork(ctx context.Context, id string, opts sharenetworks.UpdateOptsBuilder) (*sharenetworks.ShareNetwork, error) { + return sharenetworks.Update(ctx, c.client, id, opts).Extract() +} + +type sharenetworkErrorClient struct{ error } + +// NewShareNetworkErrorClient returns a ShareNetworkClient in which every method returns the given error. +func NewShareNetworkErrorClient(e error) ShareNetworkClient { + return sharenetworkErrorClient{e} +} + +func (e sharenetworkErrorClient) ListShareNetworks(_ context.Context, _ sharenetworks.ListOptsBuilder) iter.Seq2[*sharenetworks.ShareNetwork, error] { + return func(yield func(*sharenetworks.ShareNetwork, error) bool) { + yield(nil, e.error) + } +} + +func (e sharenetworkErrorClient) CreateShareNetwork(_ context.Context, _ sharenetworks.CreateOptsBuilder) (*sharenetworks.ShareNetwork, error) { + return nil, e.error +} + +func (e sharenetworkErrorClient) DeleteShareNetwork(_ context.Context, _ string) error { + return e.error +} + +func (e sharenetworkErrorClient) GetShareNetwork(_ context.Context, _ string) (*sharenetworks.ShareNetwork, error) { + return nil, e.error +} + +func (e sharenetworkErrorClient) UpdateShareNetwork(_ context.Context, _ string, _ sharenetworks.UpdateOptsBuilder) (*sharenetworks.ShareNetwork, error) { + return nil, e.error +} diff --git a/internal/osclients/user.go b/internal/osclients/user.go new file mode 100644 index 000000000..5bf564574 --- /dev/null +++ b/internal/osclients/user.go @@ -0,0 +1,104 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osclients + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/users" + "github.com/gophercloud/utils/v2/openstack/clientconfig" +) + +type UserClient interface { + ListUsers(ctx context.Context, listOpts users.ListOptsBuilder) iter.Seq2[*users.User, error] + CreateUser(ctx context.Context, opts users.CreateOptsBuilder) (*users.User, error) + DeleteUser(ctx context.Context, resourceID string) error + GetUser(ctx context.Context, resourceID string) (*users.User, error) + UpdateUser(ctx context.Context, id string, opts users.UpdateOptsBuilder) (*users.User, error) +} + +type userClient struct{ client *gophercloud.ServiceClient } + +// NewUserClient returns a new OpenStack client. +func NewUserClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (UserClient, error) { + client, err := openstack.NewIdentityV3(providerClient, gophercloud.EndpointOpts{ + Region: providerClientOpts.RegionName, + Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType), + }) + + if err != nil { + return nil, fmt.Errorf("failed to create user service client: %v", err) + } + + return &userClient{client}, nil +} + +func (c userClient) ListUsers(ctx context.Context, listOpts users.ListOptsBuilder) iter.Seq2[*users.User, error] { + pager := users.List(c.client, listOpts) + return func(yield func(*users.User, error) bool) { + _ = pager.EachPage(ctx, yieldPage(users.ExtractUsers, yield)) + } +} + +func (c userClient) CreateUser(ctx context.Context, opts users.CreateOptsBuilder) (*users.User, error) { + return users.Create(ctx, c.client, opts).Extract() +} + +func (c userClient) DeleteUser(ctx context.Context, resourceID string) error { + return users.Delete(ctx, c.client, resourceID).ExtractErr() +} + +func (c userClient) GetUser(ctx context.Context, resourceID string) (*users.User, error) { + return users.Get(ctx, c.client, resourceID).Extract() +} + +func (c userClient) UpdateUser(ctx context.Context, id string, opts users.UpdateOptsBuilder) (*users.User, error) { + return users.Update(ctx, c.client, id, opts).Extract() +} + +type userErrorClient struct{ error } + +// NewUserErrorClient returns a UserClient in which every method returns the given error. +func NewUserErrorClient(e error) UserClient { + return userErrorClient{e} +} + +func (e userErrorClient) ListUsers(_ context.Context, _ users.ListOptsBuilder) iter.Seq2[*users.User, error] { + return func(yield func(*users.User, error) bool) { + yield(nil, e.error) + } +} + +func (e userErrorClient) CreateUser(_ context.Context, _ users.CreateOptsBuilder) (*users.User, error) { + return nil, e.error +} + +func (e userErrorClient) DeleteUser(_ context.Context, _ string) error { + return e.error +} + +func (e userErrorClient) GetUser(_ context.Context, _ string) (*users.User, error) { + return nil, e.error +} + +func (e userErrorClient) UpdateUser(_ context.Context, _ string, _ users.UpdateOptsBuilder) (*users.User, error) { + return nil, e.error +} diff --git a/internal/scope/mock.go b/internal/scope/mock.go index ef959fae5..e57e4da58 100644 --- a/internal/scope/mock.go +++ b/internal/scope/mock.go @@ -34,46 +34,64 @@ import ( // MockScopeFactory implements both the ScopeFactory and ClientScope interfaces. It can be used in place of the default ProviderScopeFactory // when we want to use mocked service clients which do not attempt to connect to a running OpenStack cloud. type MockScopeFactory struct { - ComputeClient *mock.MockComputeClient - DomainClient *mock.MockDomainClient - GroupClient *mock.MockGroupClient - IdentityClient *mock.MockIdentityClient - ImageClient *mock.MockImageClient - KeyPairClient *mock.MockKeyPairClient - NetworkClient *mock.MockNetworkClient - RoleClient *mock.MockRoleClient - ServiceClient *mock.MockServiceClient - VolumeClient *mock.MockVolumeClient - VolumeTypeClient *mock.MockVolumeTypeClient + AddressScope *mock.MockAddressScopeClient + ApplicationCredentialClient *mock.MockApplicationCredentialClient + ComputeClient *mock.MockComputeClient + DomainClient *mock.MockDomainClient + EndpointClient *mock.MockEndpointClient + GroupClient *mock.MockGroupClient + IdentityClient *mock.MockIdentityClient + ImageClient *mock.MockImageClient + KeyPairClient *mock.MockKeyPairClient + NetworkClient *mock.MockNetworkClient + RoleClient *mock.MockRoleClient + RoleAssignmentClient *mock.MockRoleAssignmentClient + ServiceClient *mock.MockServiceClient + UserClient *mock.MockUserClient + VolumeClient *mock.MockVolumeClient + VolumeTypeClient *mock.MockVolumeTypeClient + ShareNetworkClient *mock.MockShareNetworkClient clientScopeCreateError error } func NewMockScopeFactory(mockCtrl *gomock.Controller) *MockScopeFactory { + addressScope := mock.NewMockAddressScopeClient(mockCtrl) + applicationcredentialClient := mock.NewMockApplicationCredentialClient(mockCtrl) computeClient := mock.NewMockComputeClient(mockCtrl) domainClient := mock.NewMockDomainClient(mockCtrl) + endpointClient := mock.NewMockEndpointClient(mockCtrl) groupClient := mock.NewMockGroupClient(mockCtrl) identityClient := mock.NewMockIdentityClient(mockCtrl) imageClient := mock.NewMockImageClient(mockCtrl) keypairClient := mock.NewMockKeyPairClient(mockCtrl) networkClient := mock.NewMockNetworkClient(mockCtrl) roleClient := mock.NewMockRoleClient(mockCtrl) + roleassignmentClient := mock.NewMockRoleAssignmentClient(mockCtrl) serviceClient := mock.NewMockServiceClient(mockCtrl) + userClient := mock.NewMockUserClient(mockCtrl) + sharenetworkClient := mock.NewMockShareNetworkClient(mockCtrl) volumeClient := mock.NewMockVolumeClient(mockCtrl) volumetypeClient := mock.NewMockVolumeTypeClient(mockCtrl) return &MockScopeFactory{ - ComputeClient: computeClient, - DomainClient: domainClient, - GroupClient: groupClient, - IdentityClient: identityClient, - ImageClient: imageClient, - KeyPairClient: keypairClient, - NetworkClient: networkClient, - RoleClient: roleClient, - ServiceClient: serviceClient, - VolumeClient: volumeClient, - VolumeTypeClient: volumetypeClient, + AddressScope: addressScope, + ApplicationCredentialClient: applicationcredentialClient, + ComputeClient: computeClient, + DomainClient: domainClient, + EndpointClient: endpointClient, + GroupClient: groupClient, + IdentityClient: identityClient, + ImageClient: imageClient, + KeyPairClient: keypairClient, + NetworkClient: networkClient, + RoleClient: roleClient, + RoleAssignmentClient: roleassignmentClient, + ServiceClient: serviceClient, + ShareNetworkClient: sharenetworkClient, + UserClient: userClient, + VolumeClient: volumeClient, + VolumeTypeClient: volumetypeClient, } } @@ -88,6 +106,10 @@ func (f *MockScopeFactory) NewClientScopeFromObject(_ context.Context, _ client. return f, nil } +func (f *MockScopeFactory) NewAddressScopeClient() (osclients.AddressScopeClient, error) { + return f.AddressScope, nil +} + func (f *MockScopeFactory) NewComputeClient() (osclients.ComputeClient, error) { return f.ComputeClient, nil } @@ -104,6 +126,10 @@ func (f *MockScopeFactory) NewIdentityClient() (osclients.IdentityClient, error) return f.IdentityClient, nil } +func (f *MockScopeFactory) NewUserClient() (osclients.UserClient, error) { + return f.UserClient, nil +} + func (f *MockScopeFactory) NewVolumeClient() (osclients.VolumeClient, error) { return f.VolumeClient, nil } @@ -120,6 +146,10 @@ func (f *MockScopeFactory) NewServiceClient() (osclients.ServiceClient, error) { return f.ServiceClient, nil } +func (f *MockScopeFactory) NewShareNetworkClient() (osclients.ShareNetworkClient, error) { + return f.ShareNetworkClient, nil +} + func (f *MockScopeFactory) NewKeyPairClient() (osclients.KeyPairClient, error) { return f.KeyPairClient, nil } @@ -132,6 +162,18 @@ func (f *MockScopeFactory) NewRoleClient() (osclients.RoleClient, error) { return f.RoleClient, nil } +func (f *MockScopeFactory) NewRoleAssignmentClient() (osclients.RoleAssignmentClient, error) { + return f.RoleAssignmentClient, nil +} + +func (f *MockScopeFactory) NewEndpointClient() (osclients.EndpointClient, error) { + return f.EndpointClient, nil +} + +func (f *MockScopeFactory) NewApplicationCredentialClient() (osclients.ApplicationCredentialClient, error) { + return f.ApplicationCredentialClient, nil +} + func (f *MockScopeFactory) ExtractToken() (*tokens.Token, error) { return &tokens.Token{ExpiresAt: time.Now().Add(24 * time.Hour)}, nil } diff --git a/internal/scope/provider.go b/internal/scope/provider.go index 65670ba60..f1207bd6c 100644 --- a/internal/scope/provider.go +++ b/internal/scope/provider.go @@ -137,6 +137,14 @@ func NewCachedProviderScope(cache *cache.LRUExpireCache, cloud clientconfig.Clou return scope, nil } +func (s *providerScope) NewAddressScopeClient() (clients.AddressScopeClient, error) { + return clients.NewAddressScopeClient(s.providerClient, s.providerClientOpts) +} + +func (s *providerScope) NewApplicationCredentialClient() (clients.ApplicationCredentialClient, error) { + return clients.NewApplicationCredentialClient(s.providerClient, s.providerClientOpts) +} + func (s *providerScope) NewComputeClient() (clients.ComputeClient, error) { return clients.NewComputeClient(s.providerClient, s.providerClientOpts) } @@ -153,6 +161,10 @@ func (s *providerScope) NewIdentityClient() (clients.IdentityClient, error) { return clients.NewIdentityClient(s.providerClient, s.providerClientOpts) } +func (s *providerScope) NewUserClient() (clients.UserClient, error) { + return clients.NewUserClient(s.providerClient, s.providerClientOpts) +} + func (s *providerScope) NewVolumeClient() (clients.VolumeClient, error) { return clients.NewVolumeClient(s.providerClient, s.providerClientOpts) } @@ -169,6 +181,14 @@ func (s *providerScope) NewServiceClient() (clients.ServiceClient, error) { return clients.NewServiceClient(s.providerClient, s.providerClientOpts) } +func (s *providerScope) NewEndpointClient() (clients.EndpointClient, error) { + return clients.NewEndpointClient(s.providerClient, s.providerClientOpts) +} + +func (s *providerScope) NewShareNetworkClient() (clients.ShareNetworkClient, error) { + return clients.NewShareNetworkClient(s.providerClient, s.providerClientOpts) +} + func (s *providerScope) NewKeyPairClient() (clients.KeyPairClient, error) { return clients.NewKeyPairClient(s.providerClient, s.providerClientOpts) } @@ -181,6 +201,10 @@ func (s *providerScope) NewRoleClient() (clients.RoleClient, error) { return clients.NewRoleClient(s.providerClient, s.providerClientOpts) } +func (s *providerScope) NewRoleAssignmentClient() (clients.RoleAssignmentClient, error) { + return clients.NewRoleAssignmentClient(s.providerClient, s.providerClientOpts) +} + func (s *providerScope) ExtractToken() (*tokens.Token, error) { client, err := openstack.NewIdentityV3(s.providerClient, gophercloud.EndpointOpts{}) if err != nil { diff --git a/internal/scope/scope.go b/internal/scope/scope.go index 7da50dc8f..4f093fe9a 100644 --- a/internal/scope/scope.go +++ b/internal/scope/scope.go @@ -48,15 +48,21 @@ type Factory interface { // Scope contains arguments common to most operations. type Scope interface { + NewAddressScopeClient() (osclients.AddressScopeClient, error) + NewApplicationCredentialClient() (osclients.ApplicationCredentialClient, error) NewComputeClient() (osclients.ComputeClient, error) NewDomainClient() (osclients.DomainClient, error) + NewEndpointClient() (osclients.EndpointClient, error) NewGroupClient() (osclients.GroupClient, error) NewIdentityClient() (osclients.IdentityClient, error) NewImageClient() (osclients.ImageClient, error) NewKeyPairClient() (osclients.KeyPairClient, error) NewNetworkClient() (osclients.NetworkClient, error) NewRoleClient() (osclients.RoleClient, error) + NewRoleAssignmentClient() (osclients.RoleAssignmentClient, error) NewServiceClient() (osclients.ServiceClient, error) + NewShareNetworkClient() (osclients.ShareNetworkClient, error) + NewUserClient() (osclients.UserClient, error) NewVolumeClient() (osclients.VolumeClient, error) NewVolumeTypeClient() (osclients.VolumeTypeClient, error) ExtractToken() (*tokens.Token, error) diff --git a/internal/util/dependency/helpers.go b/internal/util/dependency/helpers.go new file mode 100644 index 000000000..be9caa005 --- /dev/null +++ b/internal/util/dependency/helpers.go @@ -0,0 +1,68 @@ +/* +Copyright 2025 The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package dependency + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" +) + +// FetchDependency fetches a resource by name and checks if it's ready. +// Unlike GetDependency on DeletionGuardDependency, this doesn't add finalizers +// and is suitable for one-off lookups like resolving refs in import filters. +// +// Always returns an object (empty struct if not found/ready/error) for safe field access. +// +// Returns: +// - The fetched object (empty struct if name is nil, not found, not ready, or on error) +// - ReconcileStatus indicating wait state or error (nil only if name is nil or object is ready) +func FetchDependency[TP DependencyType[T], T any]( + ctx context.Context, + k8sClient client.Client, + namespace string, + name *orcv1alpha1.KubernetesNameRef, + kind string, + isReady func(TP) bool, +) (TP, progress.ReconcileStatus) { + var obj TP = new(T) + + if ptr.Deref(name, "") == "" { + return obj, nil + } + + objectKey := client.ObjectKey{Name: string(*name), Namespace: namespace} + + if err := k8sClient.Get(ctx, objectKey, obj); err != nil { + if apierrors.IsNotFound(err) { + return obj, progress.NewReconcileStatus().WaitingOnObject(kind, string(*name), progress.WaitingOnCreation) + } + return obj, progress.WrapError(fmt.Errorf("fetching %s %s: %w", kind, string(*name), err)) + } + + if !isReady(obj) { + return obj, progress.NewReconcileStatus().WaitingOnObject(kind, string(*name), progress.WaitingOnReady) + } + + return obj, nil +} diff --git a/internal/util/errors/errors.go b/internal/util/errors/errors.go index eafb5ecae..710dba16a 100644 --- a/internal/util/errors/errors.go +++ b/internal/util/errors/errors.go @@ -17,6 +17,7 @@ limitations under the License. package errors import ( + "bytes" "errors" "fmt" "net/http" @@ -51,15 +52,45 @@ func (e noMatchesError) Is(err error) bool { return err == ErrFilterMatch } +// IsRetryable returns true if err may succeed when retried without changes to +// the spec. This includes HTTP error responses other than 409 Conflict, since +// some HTTP errors (like 400 Bad Request) can be transient when a dependency +// is not yet ready in OpenStack, and server errors (5xx) are typically +// transient. +// +// Non-HTTP errors from gophercloud (e.g. client-side validation such as +// banned value_spec keys), 409 Conflict, and 501 Not Implemented are not +// retryable. The exception is Neutron quota-exceeded errors, which are +// returned as 409 but are retryable because quota can free up without spec +// changes. func IsRetryable(err error) bool { + if IsConflict(err) { + // Neutron returns 409 for quota-exceeded errors, but these are + // retryable because quota can free up without spec changes. + return isNeutronQuotaError(err) + } + + if IsNotImplementedError(err) { + return false + } + var errUnexpectedResponseCode gophercloud.ErrUnexpectedResponseCode - if errors.As(err, &errUnexpectedResponseCode) { - statusCode := errUnexpectedResponseCode.GetStatusCode() - return statusCode >= 500 && statusCode != http.StatusNotImplemented + return errors.As(err, &errUnexpectedResponseCode) +} + +// isNeutronQuotaError returns true if err is an HTTP error response whose +// body indicates a Neutron quota-exceeded condition. Neutron returns quota +// errors as 409 Conflict with an "OverQuota" type in the response body. +func isNeutronQuotaError(err error) bool { + var errUnexpectedResponseCode gophercloud.ErrUnexpectedResponseCode + if !errors.As(err, &errUnexpectedResponseCode) { + return false } - return false + return bytes.Contains(errUnexpectedResponseCode.Body, []byte("OverQuota")) } +// IsNotFound returns true if err indicates the requested OpenStack resource +// was not found (HTTP 404 or gophercloud's ErrResourceNotFound). func IsNotFound(err error) bool { if err == nil { return false @@ -78,14 +109,17 @@ func IsNotFound(err error) bool { return gophercloud.ResponseCodeIs(err, http.StatusNotFound) } +// IsInvalidError returns true if err is an HTTP 400 Bad Request response. func IsInvalidError(err error) bool { return gophercloud.ResponseCodeIs(err, http.StatusBadRequest) } +// IsConflict returns true if err is an HTTP 409 Conflict response. func IsConflict(err error) bool { return gophercloud.ResponseCodeIs(err, http.StatusConflict) } +// IsNotImplementedError returns true if err is an HTTP 501 Not Implemented response. func IsNotImplementedError(err error) bool { return gophercloud.ResponseCodeIs(err, http.StatusNotImplemented) } diff --git a/internal/util/errors/errors_test.go b/internal/util/errors/errors_test.go new file mode 100644 index 000000000..da38c5fca --- /dev/null +++ b/internal/util/errors/errors_test.go @@ -0,0 +1,108 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package errors + +import ( + "fmt" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2" +) + +func newHTTPError(statusCode int, body string) error { + return gophercloud.ErrUnexpectedResponseCode{ + Actual: statusCode, + Body: []byte(body), + } +} + +func TestIsRetryable(t *testing.T) { + tests := []struct { + name string + err error + want bool + }{ + { + name: "nil error is not retryable", + err: nil, + want: false, + }, + { + name: "non-HTTP error is not retryable", + err: fmt.Errorf("some client-side validation error"), + want: false, + }, + { + name: "409 Conflict is not retryable", + err: newHTTPError(http.StatusConflict, `{"NeutronError": {"type": "IpAddressInUse"}}`), + want: false, + }, + { + name: "409 Conflict with Neutron OverQuota is retryable", + err: newHTTPError(http.StatusConflict, `{"NeutronError": {"type": "OverQuota", "message": "Quota exceeded for resources: port."}}`), + want: true, + }, + { + name: "501 Not Implemented is not retryable", + err: newHTTPError(http.StatusNotImplemented, ""), + want: false, + }, + { + name: "400 Bad Request is retryable", + err: newHTTPError(http.StatusBadRequest, `{"NeutronError": {"type": "BadRequest"}}`), + want: true, + }, + { + name: "403 Forbidden is retryable", + err: newHTTPError(http.StatusForbidden, ""), + want: true, + }, + { + name: "500 Internal Server Error is retryable", + err: newHTTPError(http.StatusInternalServerError, ""), + want: true, + }, + { + name: "503 Service Unavailable is retryable", + err: newHTTPError(http.StatusServiceUnavailable, ""), + want: true, + }, + { + name: "wrapped non-HTTP error is not retryable", + err: fmt.Errorf("wrapping: %w", fmt.Errorf("banned key")), + want: false, + }, + { + name: "wrapped 409 is not retryable", + err: fmt.Errorf("wrapping: %w", newHTTPError(http.StatusConflict, "")), + want: false, + }, + { + name: "wrapped 409 with OverQuota is retryable", + err: fmt.Errorf("wrapping: %w", newHTTPError(http.StatusConflict, `{"NeutronError": {"type": "OverQuota"}}`)), + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsRetryable(tt.err); got != tt.want { + t.Errorf("IsRetryable() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/kuttl-test.yaml b/kuttl-test.yaml index d499782e6..90fc98dde 100644 --- a/kuttl-test.yaml +++ b/kuttl-test.yaml @@ -2,7 +2,10 @@ apiVersion: kuttl.dev/v1beta1 kind: TestSuite testDirs: +- ./internal/controllers/addressscope/tests/ +- ./internal/controllers/applicationcredential/tests/ - ./internal/controllers/domain/tests/ +- ./internal/controllers/endpoint/tests/ - ./internal/controllers/flavor/tests/ - ./internal/controllers/floatingip/tests/ - ./internal/controllers/group/tests/ @@ -12,13 +15,17 @@ testDirs: - ./internal/controllers/port/tests/ - ./internal/controllers/project/tests/ - ./internal/controllers/role/tests/ +- ./internal/controllers/roleassignment/tests/ - ./internal/controllers/router/tests/ - ./internal/controllers/routerinterface/tests/ - ./internal/controllers/securitygroup/tests/ - ./internal/controllers/server/tests/ - ./internal/controllers/servergroup/tests/ - ./internal/controllers/service/tests/ +- ./internal/controllers/sharenetwork/tests/ - ./internal/controllers/subnet/tests/ +- ./internal/controllers/trunk/tests/ +- ./internal/controllers/user/tests/ - ./internal/controllers/volume/tests/ - ./internal/controllers/volumetype/tests/ timeout: 240 diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/address.go b/pkg/clients/applyconfiguration/api/v1alpha1/address.go index 74478a9e0..7db825b3b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/address.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/address.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/addressscope.go b/pkg/clients/applyconfiguration/api/v1alpha1/addressscope.go new file mode 100644 index 000000000..7b43dfb87 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/addressscope.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// AddressScopeApplyConfiguration represents a declarative configuration of the AddressScope type for use +// with apply. +type AddressScopeApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *AddressScopeSpecApplyConfiguration `json:"spec,omitempty"` + Status *AddressScopeStatusApplyConfiguration `json:"status,omitempty"` +} + +// AddressScope constructs a declarative configuration of the AddressScope type for use with +// apply. +func AddressScope(name, namespace string) *AddressScopeApplyConfiguration { + b := &AddressScopeApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("AddressScope") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractAddressScope extracts the applied configuration owned by fieldManager from +// addressScope. If no managedFields are found in addressScope for fieldManager, a +// AddressScopeApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// addressScope must be a unmodified AddressScope API object that was retrieved from the Kubernetes API. +// ExtractAddressScope provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractAddressScope(addressScope *apiv1alpha1.AddressScope, fieldManager string) (*AddressScopeApplyConfiguration, error) { + return extractAddressScope(addressScope, fieldManager, "") +} + +// ExtractAddressScopeStatus is the same as ExtractAddressScope except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractAddressScopeStatus(addressScope *apiv1alpha1.AddressScope, fieldManager string) (*AddressScopeApplyConfiguration, error) { + return extractAddressScope(addressScope, fieldManager, "status") +} + +func extractAddressScope(addressScope *apiv1alpha1.AddressScope, fieldManager string, subresource string) (*AddressScopeApplyConfiguration, error) { + b := &AddressScopeApplyConfiguration{} + err := managedfields.ExtractInto(addressScope, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScope"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(addressScope.Name) + b.WithNamespace(addressScope.Namespace) + + b.WithKind("AddressScope") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b AddressScopeApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithKind(value string) *AddressScopeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithAPIVersion(value string) *AddressScopeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithName(value string) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithGenerateName(value string) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithNamespace(value string) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithUID(value types.UID) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithResourceVersion(value string) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithGeneration(value int64) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithCreationTimestamp(value metav1.Time) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *AddressScopeApplyConfiguration) WithLabels(entries map[string]string) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *AddressScopeApplyConfiguration) WithAnnotations(entries map[string]string) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *AddressScopeApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *AddressScopeApplyConfiguration) WithFinalizers(values ...string) *AddressScopeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *AddressScopeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithSpec(value *AddressScopeSpecApplyConfiguration) *AddressScopeApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *AddressScopeApplyConfiguration) WithStatus(value *AddressScopeStatusApplyConfiguration) *AddressScopeApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *AddressScopeApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *AddressScopeApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *AddressScopeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *AddressScopeApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/addressscopefilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopefilter.go new file mode 100644 index 000000000..646451d21 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopefilter.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// AddressScopeFilterApplyConfiguration represents a declarative configuration of the AddressScopeFilter type for use +// with apply. +type AddressScopeFilterApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + IPVersion *apiv1alpha1.IPVersion `json:"ipVersion,omitempty"` + Shared *bool `json:"shared,omitempty"` +} + +// AddressScopeFilterApplyConfiguration constructs a declarative configuration of the AddressScopeFilter type for use with +// apply. +func AddressScopeFilter() *AddressScopeFilterApplyConfiguration { + return &AddressScopeFilterApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *AddressScopeFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *AddressScopeFilterApplyConfiguration { + b.Name = &value + return b +} + +// WithProjectRef sets the ProjectRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectRef field is set to the value of the last call. +func (b *AddressScopeFilterApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *AddressScopeFilterApplyConfiguration { + b.ProjectRef = &value + return b +} + +// WithIPVersion sets the IPVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the IPVersion field is set to the value of the last call. +func (b *AddressScopeFilterApplyConfiguration) WithIPVersion(value apiv1alpha1.IPVersion) *AddressScopeFilterApplyConfiguration { + b.IPVersion = &value + return b +} + +// WithShared sets the Shared field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Shared field is set to the value of the last call. +func (b *AddressScopeFilterApplyConfiguration) WithShared(value bool) *AddressScopeFilterApplyConfiguration { + b.Shared = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/addressscopeimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopeimport.go new file mode 100644 index 000000000..a1e787e7a --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopeimport.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// AddressScopeImportApplyConfiguration represents a declarative configuration of the AddressScopeImport type for use +// with apply. +type AddressScopeImportApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Filter *AddressScopeFilterApplyConfiguration `json:"filter,omitempty"` +} + +// AddressScopeImportApplyConfiguration constructs a declarative configuration of the AddressScopeImport type for use with +// apply. +func AddressScopeImport() *AddressScopeImportApplyConfiguration { + return &AddressScopeImportApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *AddressScopeImportApplyConfiguration) WithID(value string) *AddressScopeImportApplyConfiguration { + b.ID = &value + return b +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *AddressScopeImportApplyConfiguration) WithFilter(value *AddressScopeFilterApplyConfiguration) *AddressScopeImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/addressscoperesourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/addressscoperesourcespec.go new file mode 100644 index 000000000..8fb3db96b --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/addressscoperesourcespec.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// AddressScopeResourceSpecApplyConfiguration represents a declarative configuration of the AddressScopeResourceSpec type for use +// with apply. +type AddressScopeResourceSpecApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + IPVersion *apiv1alpha1.IPVersion `json:"ipVersion,omitempty"` + Shared *bool `json:"shared,omitempty"` +} + +// AddressScopeResourceSpecApplyConfiguration constructs a declarative configuration of the AddressScopeResourceSpec type for use with +// apply. +func AddressScopeResourceSpec() *AddressScopeResourceSpecApplyConfiguration { + return &AddressScopeResourceSpecApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *AddressScopeResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *AddressScopeResourceSpecApplyConfiguration { + b.Name = &value + return b +} + +// WithProjectRef sets the ProjectRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectRef field is set to the value of the last call. +func (b *AddressScopeResourceSpecApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *AddressScopeResourceSpecApplyConfiguration { + b.ProjectRef = &value + return b +} + +// WithIPVersion sets the IPVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the IPVersion field is set to the value of the last call. +func (b *AddressScopeResourceSpecApplyConfiguration) WithIPVersion(value apiv1alpha1.IPVersion) *AddressScopeResourceSpecApplyConfiguration { + b.IPVersion = &value + return b +} + +// WithShared sets the Shared field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Shared field is set to the value of the last call. +func (b *AddressScopeResourceSpecApplyConfiguration) WithShared(value bool) *AddressScopeResourceSpecApplyConfiguration { + b.Shared = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/addressscoperesourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/addressscoperesourcestatus.go new file mode 100644 index 000000000..baae40d75 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/addressscoperesourcestatus.go @@ -0,0 +1,66 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// AddressScopeResourceStatusApplyConfiguration represents a declarative configuration of the AddressScopeResourceStatus type for use +// with apply. +type AddressScopeResourceStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + ProjectID *string `json:"projectID,omitempty"` + IPVersion *int32 `json:"ipVersion,omitempty"` + Shared *bool `json:"shared,omitempty"` +} + +// AddressScopeResourceStatusApplyConfiguration constructs a declarative configuration of the AddressScopeResourceStatus type for use with +// apply. +func AddressScopeResourceStatus() *AddressScopeResourceStatusApplyConfiguration { + return &AddressScopeResourceStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *AddressScopeResourceStatusApplyConfiguration) WithName(value string) *AddressScopeResourceStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithProjectID sets the ProjectID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectID field is set to the value of the last call. +func (b *AddressScopeResourceStatusApplyConfiguration) WithProjectID(value string) *AddressScopeResourceStatusApplyConfiguration { + b.ProjectID = &value + return b +} + +// WithIPVersion sets the IPVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the IPVersion field is set to the value of the last call. +func (b *AddressScopeResourceStatusApplyConfiguration) WithIPVersion(value int32) *AddressScopeResourceStatusApplyConfiguration { + b.IPVersion = &value + return b +} + +// WithShared sets the Shared field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Shared field is set to the value of the last call. +func (b *AddressScopeResourceStatusApplyConfiguration) WithShared(value bool) *AddressScopeResourceStatusApplyConfiguration { + b.Shared = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/addressscopespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopespec.go new file mode 100644 index 000000000..1ef5b5cee --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopespec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// AddressScopeSpecApplyConfiguration represents a declarative configuration of the AddressScopeSpec type for use +// with apply. +type AddressScopeSpecApplyConfiguration struct { + Import *AddressScopeImportApplyConfiguration `json:"import,omitempty"` + Resource *AddressScopeResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// AddressScopeSpecApplyConfiguration constructs a declarative configuration of the AddressScopeSpec type for use with +// apply. +func AddressScopeSpec() *AddressScopeSpecApplyConfiguration { + return &AddressScopeSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *AddressScopeSpecApplyConfiguration) WithImport(value *AddressScopeImportApplyConfiguration) *AddressScopeSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *AddressScopeSpecApplyConfiguration) WithResource(value *AddressScopeResourceSpecApplyConfiguration) *AddressScopeSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *AddressScopeSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *AddressScopeSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *AddressScopeSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *AddressScopeSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *AddressScopeSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *AddressScopeSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *AddressScopeSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *AddressScopeSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/addressscopestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopestatus.go new file mode 100644 index 000000000..b7ecb594f --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/addressscopestatus.go @@ -0,0 +1,76 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// AddressScopeStatusApplyConfiguration represents a declarative configuration of the AddressScopeStatus type for use +// with apply. +type AddressScopeStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *AddressScopeResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// AddressScopeStatusApplyConfiguration constructs a declarative configuration of the AddressScopeStatus type for use with +// apply. +func AddressScopeStatus() *AddressScopeStatusApplyConfiguration { + return &AddressScopeStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *AddressScopeStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *AddressScopeStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *AddressScopeStatusApplyConfiguration) WithID(value string) *AddressScopeStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *AddressScopeStatusApplyConfiguration) WithResource(value *AddressScopeResourceStatusApplyConfiguration) *AddressScopeStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *AddressScopeStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *AddressScopeStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/allocationpool.go b/pkg/clients/applyconfiguration/api/v1alpha1/allocationpool.go index d152ed380..bf3667ad7 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/allocationpool.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/allocationpool.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/allocationpoolstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/allocationpoolstatus.go index a806531d6..a66c82e05 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/allocationpoolstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/allocationpoolstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspair.go b/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspair.go index 48d77abbe..b80e96c5d 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspair.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspair.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspairstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspairstatus.go index d18d0a5d8..19ec2e80f 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspairstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/allowedaddresspairstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredential.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredential.go new file mode 100644 index 000000000..db5eb36e8 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredential.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ApplicationCredentialApplyConfiguration represents a declarative configuration of the ApplicationCredential type for use +// with apply. +type ApplicationCredentialApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *ApplicationCredentialSpecApplyConfiguration `json:"spec,omitempty"` + Status *ApplicationCredentialStatusApplyConfiguration `json:"status,omitempty"` +} + +// ApplicationCredential constructs a declarative configuration of the ApplicationCredential type for use with +// apply. +func ApplicationCredential(name, namespace string) *ApplicationCredentialApplyConfiguration { + b := &ApplicationCredentialApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("ApplicationCredential") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractApplicationCredential extracts the applied configuration owned by fieldManager from +// applicationCredential. If no managedFields are found in applicationCredential for fieldManager, a +// ApplicationCredentialApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// applicationCredential must be a unmodified ApplicationCredential API object that was retrieved from the Kubernetes API. +// ExtractApplicationCredential provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractApplicationCredential(applicationCredential *apiv1alpha1.ApplicationCredential, fieldManager string) (*ApplicationCredentialApplyConfiguration, error) { + return extractApplicationCredential(applicationCredential, fieldManager, "") +} + +// ExtractApplicationCredentialStatus is the same as ExtractApplicationCredential except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractApplicationCredentialStatus(applicationCredential *apiv1alpha1.ApplicationCredential, fieldManager string) (*ApplicationCredentialApplyConfiguration, error) { + return extractApplicationCredential(applicationCredential, fieldManager, "status") +} + +func extractApplicationCredential(applicationCredential *apiv1alpha1.ApplicationCredential, fieldManager string, subresource string) (*ApplicationCredentialApplyConfiguration, error) { + b := &ApplicationCredentialApplyConfiguration{} + err := managedfields.ExtractInto(applicationCredential, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredential"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(applicationCredential.Name) + b.WithNamespace(applicationCredential.Namespace) + + b.WithKind("ApplicationCredential") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b ApplicationCredentialApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithKind(value string) *ApplicationCredentialApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithAPIVersion(value string) *ApplicationCredentialApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithName(value string) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithGenerateName(value string) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithNamespace(value string) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithUID(value types.UID) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithResourceVersion(value string) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithGeneration(value int64) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ApplicationCredentialApplyConfiguration) WithLabels(entries map[string]string) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ApplicationCredentialApplyConfiguration) WithAnnotations(entries map[string]string) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *ApplicationCredentialApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *ApplicationCredentialApplyConfiguration) WithFinalizers(values ...string) *ApplicationCredentialApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *ApplicationCredentialApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithSpec(value *ApplicationCredentialSpecApplyConfiguration) *ApplicationCredentialApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ApplicationCredentialApplyConfiguration) WithStatus(value *ApplicationCredentialStatusApplyConfiguration) *ApplicationCredentialApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *ApplicationCredentialApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *ApplicationCredentialApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ApplicationCredentialApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *ApplicationCredentialApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialaccessrule.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialaccessrule.go new file mode 100644 index 000000000..4b485c5cb --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialaccessrule.go @@ -0,0 +1,61 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// ApplicationCredentialAccessRuleApplyConfiguration represents a declarative configuration of the ApplicationCredentialAccessRule type for use +// with apply. +type ApplicationCredentialAccessRuleApplyConfiguration struct { + Path *string `json:"path,omitempty"` + Method *apiv1alpha1.HTTPMethod `json:"method,omitempty"` + ServiceRef *apiv1alpha1.KubernetesNameRef `json:"serviceRef,omitempty"` +} + +// ApplicationCredentialAccessRuleApplyConfiguration constructs a declarative configuration of the ApplicationCredentialAccessRule type for use with +// apply. +func ApplicationCredentialAccessRule() *ApplicationCredentialAccessRuleApplyConfiguration { + return &ApplicationCredentialAccessRuleApplyConfiguration{} +} + +// WithPath sets the Path field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Path field is set to the value of the last call. +func (b *ApplicationCredentialAccessRuleApplyConfiguration) WithPath(value string) *ApplicationCredentialAccessRuleApplyConfiguration { + b.Path = &value + return b +} + +// WithMethod sets the Method field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Method field is set to the value of the last call. +func (b *ApplicationCredentialAccessRuleApplyConfiguration) WithMethod(value apiv1alpha1.HTTPMethod) *ApplicationCredentialAccessRuleApplyConfiguration { + b.Method = &value + return b +} + +// WithServiceRef sets the ServiceRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServiceRef field is set to the value of the last call. +func (b *ApplicationCredentialAccessRuleApplyConfiguration) WithServiceRef(value apiv1alpha1.KubernetesNameRef) *ApplicationCredentialAccessRuleApplyConfiguration { + b.ServiceRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialaccessrulestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialaccessrulestatus.go new file mode 100644 index 000000000..9624a3d3f --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialaccessrulestatus.go @@ -0,0 +1,66 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ApplicationCredentialAccessRuleStatusApplyConfiguration represents a declarative configuration of the ApplicationCredentialAccessRuleStatus type for use +// with apply. +type ApplicationCredentialAccessRuleStatusApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Path *string `json:"path,omitempty"` + Method *string `json:"method,omitempty"` + Service *string `json:"service,omitempty"` +} + +// ApplicationCredentialAccessRuleStatusApplyConfiguration constructs a declarative configuration of the ApplicationCredentialAccessRuleStatus type for use with +// apply. +func ApplicationCredentialAccessRuleStatus() *ApplicationCredentialAccessRuleStatusApplyConfiguration { + return &ApplicationCredentialAccessRuleStatusApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *ApplicationCredentialAccessRuleStatusApplyConfiguration) WithID(value string) *ApplicationCredentialAccessRuleStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithPath sets the Path field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Path field is set to the value of the last call. +func (b *ApplicationCredentialAccessRuleStatusApplyConfiguration) WithPath(value string) *ApplicationCredentialAccessRuleStatusApplyConfiguration { + b.Path = &value + return b +} + +// WithMethod sets the Method field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Method field is set to the value of the last call. +func (b *ApplicationCredentialAccessRuleStatusApplyConfiguration) WithMethod(value string) *ApplicationCredentialAccessRuleStatusApplyConfiguration { + b.Method = &value + return b +} + +// WithService sets the Service field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Service field is set to the value of the last call. +func (b *ApplicationCredentialAccessRuleStatusApplyConfiguration) WithService(value string) *ApplicationCredentialAccessRuleStatusApplyConfiguration { + b.Service = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialfilter.go new file mode 100644 index 000000000..d3d4a136b --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialfilter.go @@ -0,0 +1,61 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// ApplicationCredentialFilterApplyConfiguration represents a declarative configuration of the ApplicationCredentialFilter type for use +// with apply. +type ApplicationCredentialFilterApplyConfiguration struct { + UserRef *apiv1alpha1.KubernetesNameRef `json:"userRef,omitempty"` + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` +} + +// ApplicationCredentialFilterApplyConfiguration constructs a declarative configuration of the ApplicationCredentialFilter type for use with +// apply. +func ApplicationCredentialFilter() *ApplicationCredentialFilterApplyConfiguration { + return &ApplicationCredentialFilterApplyConfiguration{} +} + +// WithUserRef sets the UserRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UserRef field is set to the value of the last call. +func (b *ApplicationCredentialFilterApplyConfiguration) WithUserRef(value apiv1alpha1.KubernetesNameRef) *ApplicationCredentialFilterApplyConfiguration { + b.UserRef = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ApplicationCredentialFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *ApplicationCredentialFilterApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *ApplicationCredentialFilterApplyConfiguration) WithDescription(value string) *ApplicationCredentialFilterApplyConfiguration { + b.Description = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialimport.go new file mode 100644 index 000000000..b84df0314 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialimport.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ApplicationCredentialImportApplyConfiguration represents a declarative configuration of the ApplicationCredentialImport type for use +// with apply. +type ApplicationCredentialImportApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Filter *ApplicationCredentialFilterApplyConfiguration `json:"filter,omitempty"` +} + +// ApplicationCredentialImportApplyConfiguration constructs a declarative configuration of the ApplicationCredentialImport type for use with +// apply. +func ApplicationCredentialImport() *ApplicationCredentialImportApplyConfiguration { + return &ApplicationCredentialImportApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *ApplicationCredentialImportApplyConfiguration) WithID(value string) *ApplicationCredentialImportApplyConfiguration { + b.ID = &value + return b +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *ApplicationCredentialImportApplyConfiguration) WithFilter(value *ApplicationCredentialFilterApplyConfiguration) *ApplicationCredentialImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialresourcespec.go new file mode 100644 index 000000000..fd1c8bc5c --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialresourcespec.go @@ -0,0 +1,114 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ApplicationCredentialResourceSpecApplyConfiguration represents a declarative configuration of the ApplicationCredentialResourceSpec type for use +// with apply. +type ApplicationCredentialResourceSpecApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + UserRef *apiv1alpha1.KubernetesNameRef `json:"userRef,omitempty"` + Unrestricted *bool `json:"unrestricted,omitempty"` + SecretRef *apiv1alpha1.KubernetesNameRef `json:"secretRef,omitempty"` + RoleRefs []apiv1alpha1.KubernetesNameRef `json:"roleRefs,omitempty"` + AccessRules []ApplicationCredentialAccessRuleApplyConfiguration `json:"accessRules,omitempty"` + ExpiresAt *v1.Time `json:"expiresAt,omitempty"` +} + +// ApplicationCredentialResourceSpecApplyConfiguration constructs a declarative configuration of the ApplicationCredentialResourceSpec type for use with +// apply. +func ApplicationCredentialResourceSpec() *ApplicationCredentialResourceSpecApplyConfiguration { + return &ApplicationCredentialResourceSpecApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *ApplicationCredentialResourceSpecApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithDescription(value string) *ApplicationCredentialResourceSpecApplyConfiguration { + b.Description = &value + return b +} + +// WithUserRef sets the UserRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UserRef field is set to the value of the last call. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithUserRef(value apiv1alpha1.KubernetesNameRef) *ApplicationCredentialResourceSpecApplyConfiguration { + b.UserRef = &value + return b +} + +// WithUnrestricted sets the Unrestricted field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Unrestricted field is set to the value of the last call. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithUnrestricted(value bool) *ApplicationCredentialResourceSpecApplyConfiguration { + b.Unrestricted = &value + return b +} + +// WithSecretRef sets the SecretRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SecretRef field is set to the value of the last call. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithSecretRef(value apiv1alpha1.KubernetesNameRef) *ApplicationCredentialResourceSpecApplyConfiguration { + b.SecretRef = &value + return b +} + +// WithRoleRefs adds the given value to the RoleRefs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the RoleRefs field. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithRoleRefs(values ...apiv1alpha1.KubernetesNameRef) *ApplicationCredentialResourceSpecApplyConfiguration { + for i := range values { + b.RoleRefs = append(b.RoleRefs, values[i]) + } + return b +} + +// WithAccessRules adds the given value to the AccessRules field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the AccessRules field. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithAccessRules(values ...*ApplicationCredentialAccessRuleApplyConfiguration) *ApplicationCredentialResourceSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithAccessRules") + } + b.AccessRules = append(b.AccessRules, *values[i]) + } + return b +} + +// WithExpiresAt sets the ExpiresAt field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ExpiresAt field is set to the value of the last call. +func (b *ApplicationCredentialResourceSpecApplyConfiguration) WithExpiresAt(value v1.Time) *ApplicationCredentialResourceSpecApplyConfiguration { + b.ExpiresAt = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialresourcestatus.go new file mode 100644 index 000000000..04e3eb95a --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialresourcestatus.go @@ -0,0 +1,107 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ApplicationCredentialResourceStatusApplyConfiguration represents a declarative configuration of the ApplicationCredentialResourceStatus type for use +// with apply. +type ApplicationCredentialResourceStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + Unrestricted *bool `json:"unrestricted,omitempty"` + ProjectID *string `json:"projectID,omitempty"` + Roles []ApplicationCredentialRoleStatusApplyConfiguration `json:"roles,omitempty"` + ExpiresAt *v1.Time `json:"expiresAt,omitempty"` + AccessRules []ApplicationCredentialAccessRuleStatusApplyConfiguration `json:"accessRules,omitempty"` +} + +// ApplicationCredentialResourceStatusApplyConfiguration constructs a declarative configuration of the ApplicationCredentialResourceStatus type for use with +// apply. +func ApplicationCredentialResourceStatus() *ApplicationCredentialResourceStatusApplyConfiguration { + return &ApplicationCredentialResourceStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ApplicationCredentialResourceStatusApplyConfiguration) WithName(value string) *ApplicationCredentialResourceStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *ApplicationCredentialResourceStatusApplyConfiguration) WithDescription(value string) *ApplicationCredentialResourceStatusApplyConfiguration { + b.Description = &value + return b +} + +// WithUnrestricted sets the Unrestricted field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Unrestricted field is set to the value of the last call. +func (b *ApplicationCredentialResourceStatusApplyConfiguration) WithUnrestricted(value bool) *ApplicationCredentialResourceStatusApplyConfiguration { + b.Unrestricted = &value + return b +} + +// WithProjectID sets the ProjectID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectID field is set to the value of the last call. +func (b *ApplicationCredentialResourceStatusApplyConfiguration) WithProjectID(value string) *ApplicationCredentialResourceStatusApplyConfiguration { + b.ProjectID = &value + return b +} + +// WithRoles adds the given value to the Roles field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Roles field. +func (b *ApplicationCredentialResourceStatusApplyConfiguration) WithRoles(values ...*ApplicationCredentialRoleStatusApplyConfiguration) *ApplicationCredentialResourceStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithRoles") + } + b.Roles = append(b.Roles, *values[i]) + } + return b +} + +// WithExpiresAt sets the ExpiresAt field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ExpiresAt field is set to the value of the last call. +func (b *ApplicationCredentialResourceStatusApplyConfiguration) WithExpiresAt(value v1.Time) *ApplicationCredentialResourceStatusApplyConfiguration { + b.ExpiresAt = &value + return b +} + +// WithAccessRules adds the given value to the AccessRules field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the AccessRules field. +func (b *ApplicationCredentialResourceStatusApplyConfiguration) WithAccessRules(values ...*ApplicationCredentialAccessRuleStatusApplyConfiguration) *ApplicationCredentialResourceStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithAccessRules") + } + b.AccessRules = append(b.AccessRules, *values[i]) + } + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialrolestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialrolestatus.go new file mode 100644 index 000000000..c3e88c115 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialrolestatus.go @@ -0,0 +1,57 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ApplicationCredentialRoleStatusApplyConfiguration represents a declarative configuration of the ApplicationCredentialRoleStatus type for use +// with apply. +type ApplicationCredentialRoleStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + ID *string `json:"id,omitempty"` + DomainID *string `json:"domainID,omitempty"` +} + +// ApplicationCredentialRoleStatusApplyConfiguration constructs a declarative configuration of the ApplicationCredentialRoleStatus type for use with +// apply. +func ApplicationCredentialRoleStatus() *ApplicationCredentialRoleStatusApplyConfiguration { + return &ApplicationCredentialRoleStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ApplicationCredentialRoleStatusApplyConfiguration) WithName(value string) *ApplicationCredentialRoleStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *ApplicationCredentialRoleStatusApplyConfiguration) WithID(value string) *ApplicationCredentialRoleStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithDomainID sets the DomainID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainID field is set to the value of the last call. +func (b *ApplicationCredentialRoleStatusApplyConfiguration) WithDomainID(value string) *ApplicationCredentialRoleStatusApplyConfiguration { + b.DomainID = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialspec.go new file mode 100644 index 000000000..09f1178b1 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialspec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ApplicationCredentialSpecApplyConfiguration represents a declarative configuration of the ApplicationCredentialSpec type for use +// with apply. +type ApplicationCredentialSpecApplyConfiguration struct { + Import *ApplicationCredentialImportApplyConfiguration `json:"import,omitempty"` + Resource *ApplicationCredentialResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// ApplicationCredentialSpecApplyConfiguration constructs a declarative configuration of the ApplicationCredentialSpec type for use with +// apply. +func ApplicationCredentialSpec() *ApplicationCredentialSpecApplyConfiguration { + return &ApplicationCredentialSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *ApplicationCredentialSpecApplyConfiguration) WithImport(value *ApplicationCredentialImportApplyConfiguration) *ApplicationCredentialSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *ApplicationCredentialSpecApplyConfiguration) WithResource(value *ApplicationCredentialResourceSpecApplyConfiguration) *ApplicationCredentialSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *ApplicationCredentialSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *ApplicationCredentialSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *ApplicationCredentialSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *ApplicationCredentialSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *ApplicationCredentialSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *ApplicationCredentialSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *ApplicationCredentialSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *ApplicationCredentialSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialstatus.go new file mode 100644 index 000000000..70e271a57 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/applicationcredentialstatus.go @@ -0,0 +1,76 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ApplicationCredentialStatusApplyConfiguration represents a declarative configuration of the ApplicationCredentialStatus type for use +// with apply. +type ApplicationCredentialStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *ApplicationCredentialResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// ApplicationCredentialStatusApplyConfiguration constructs a declarative configuration of the ApplicationCredentialStatus type for use with +// apply. +func ApplicationCredentialStatus() *ApplicationCredentialStatusApplyConfiguration { + return &ApplicationCredentialStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *ApplicationCredentialStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *ApplicationCredentialStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *ApplicationCredentialStatusApplyConfiguration) WithID(value string) *ApplicationCredentialStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *ApplicationCredentialStatusApplyConfiguration) WithResource(value *ApplicationCredentialResourceStatusApplyConfiguration) *ApplicationCredentialStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *ApplicationCredentialStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *ApplicationCredentialStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/cloudcredentialsreference.go b/pkg/clients/applyconfiguration/api/v1alpha1/cloudcredentialsreference.go index 455c0eb1e..d619ae9ff 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/cloudcredentialsreference.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/cloudcredentialsreference.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/domain.go b/pkg/clients/applyconfiguration/api/v1alpha1/domain.go index 5f1b4216b..b8748feeb 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/domain.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/domain.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/domainfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/domainfilter.go index bed3c4ef7..49152b6a3 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/domainfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/domainfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/domainimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/domainimport.go index 26198ccab..a208643cd 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/domainimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/domainimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcespec.go index c18282d4f..1b9a0ea6b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcestatus.go index ca5d524f5..91911434a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/domainresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/domainspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/domainspec.go index 2c72fdef4..dc2da0444 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/domainspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/domainspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // DomainSpecApplyConfiguration represents a declarative configuration of the DomainSpec type for use @@ -29,6 +30,7 @@ type DomainSpecApplyConfiguration struct { Resource *DomainResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *DomainSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsA return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *DomainSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *DomainSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/domainstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/domainstatus.go index 0294b7a06..c87fc50e1 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/domainstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/domainstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // DomainStatusApplyConfiguration represents a declarative configuration of the DomainStatus type for use // with apply. type DomainStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *DomainResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *DomainResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // DomainStatusApplyConfiguration constructs a declarative configuration of the DomainStatus type for use with @@ -64,3 +66,11 @@ func (b *DomainStatusApplyConfiguration) WithResource(value *DomainResourceStatu b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *DomainStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *DomainStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/endpoint.go b/pkg/clients/applyconfiguration/api/v1alpha1/endpoint.go new file mode 100644 index 000000000..6c1f5e897 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/endpoint.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// EndpointApplyConfiguration represents a declarative configuration of the Endpoint type for use +// with apply. +type EndpointApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *EndpointSpecApplyConfiguration `json:"spec,omitempty"` + Status *EndpointStatusApplyConfiguration `json:"status,omitempty"` +} + +// Endpoint constructs a declarative configuration of the Endpoint type for use with +// apply. +func Endpoint(name, namespace string) *EndpointApplyConfiguration { + b := &EndpointApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("Endpoint") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractEndpoint extracts the applied configuration owned by fieldManager from +// endpoint. If no managedFields are found in endpoint for fieldManager, a +// EndpointApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// endpoint must be a unmodified Endpoint API object that was retrieved from the Kubernetes API. +// ExtractEndpoint provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractEndpoint(endpoint *apiv1alpha1.Endpoint, fieldManager string) (*EndpointApplyConfiguration, error) { + return extractEndpoint(endpoint, fieldManager, "") +} + +// ExtractEndpointStatus is the same as ExtractEndpoint except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractEndpointStatus(endpoint *apiv1alpha1.Endpoint, fieldManager string) (*EndpointApplyConfiguration, error) { + return extractEndpoint(endpoint, fieldManager, "status") +} + +func extractEndpoint(endpoint *apiv1alpha1.Endpoint, fieldManager string, subresource string) (*EndpointApplyConfiguration, error) { + b := &EndpointApplyConfiguration{} + err := managedfields.ExtractInto(endpoint, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Endpoint"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(endpoint.Name) + b.WithNamespace(endpoint.Namespace) + + b.WithKind("Endpoint") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b EndpointApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithKind(value string) *EndpointApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithAPIVersion(value string) *EndpointApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithName(value string) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithGenerateName(value string) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithNamespace(value string) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithUID(value types.UID) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithResourceVersion(value string) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithGeneration(value int64) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithCreationTimestamp(value metav1.Time) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *EndpointApplyConfiguration) WithLabels(entries map[string]string) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *EndpointApplyConfiguration) WithAnnotations(entries map[string]string) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *EndpointApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *EndpointApplyConfiguration) WithFinalizers(values ...string) *EndpointApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *EndpointApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithSpec(value *EndpointSpecApplyConfiguration) *EndpointApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *EndpointApplyConfiguration) WithStatus(value *EndpointStatusApplyConfiguration) *EndpointApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *EndpointApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *EndpointApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *EndpointApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *EndpointApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/endpointfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/endpointfilter.go new file mode 100644 index 000000000..fe33276e4 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/endpointfilter.go @@ -0,0 +1,61 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// EndpointFilterApplyConfiguration represents a declarative configuration of the EndpointFilter type for use +// with apply. +type EndpointFilterApplyConfiguration struct { + Interface *string `json:"interface,omitempty"` + ServiceRef *apiv1alpha1.KubernetesNameRef `json:"serviceRef,omitempty"` + URL *string `json:"url,omitempty"` +} + +// EndpointFilterApplyConfiguration constructs a declarative configuration of the EndpointFilter type for use with +// apply. +func EndpointFilter() *EndpointFilterApplyConfiguration { + return &EndpointFilterApplyConfiguration{} +} + +// WithInterface sets the Interface field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Interface field is set to the value of the last call. +func (b *EndpointFilterApplyConfiguration) WithInterface(value string) *EndpointFilterApplyConfiguration { + b.Interface = &value + return b +} + +// WithServiceRef sets the ServiceRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServiceRef field is set to the value of the last call. +func (b *EndpointFilterApplyConfiguration) WithServiceRef(value apiv1alpha1.KubernetesNameRef) *EndpointFilterApplyConfiguration { + b.ServiceRef = &value + return b +} + +// WithURL sets the URL field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the URL field is set to the value of the last call. +func (b *EndpointFilterApplyConfiguration) WithURL(value string) *EndpointFilterApplyConfiguration { + b.URL = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/endpointimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/endpointimport.go new file mode 100644 index 000000000..8d6cae433 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/endpointimport.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// EndpointImportApplyConfiguration represents a declarative configuration of the EndpointImport type for use +// with apply. +type EndpointImportApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Filter *EndpointFilterApplyConfiguration `json:"filter,omitempty"` +} + +// EndpointImportApplyConfiguration constructs a declarative configuration of the EndpointImport type for use with +// apply. +func EndpointImport() *EndpointImportApplyConfiguration { + return &EndpointImportApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *EndpointImportApplyConfiguration) WithID(value string) *EndpointImportApplyConfiguration { + b.ID = &value + return b +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *EndpointImportApplyConfiguration) WithFilter(value *EndpointFilterApplyConfiguration) *EndpointImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/endpointresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/endpointresourcespec.go new file mode 100644 index 000000000..ff59ccce4 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/endpointresourcespec.go @@ -0,0 +1,79 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// EndpointResourceSpecApplyConfiguration represents a declarative configuration of the EndpointResourceSpec type for use +// with apply. +type EndpointResourceSpecApplyConfiguration struct { + Description *string `json:"description,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Interface *string `json:"interface,omitempty"` + URL *string `json:"url,omitempty"` + ServiceRef *apiv1alpha1.KubernetesNameRef `json:"serviceRef,omitempty"` +} + +// EndpointResourceSpecApplyConfiguration constructs a declarative configuration of the EndpointResourceSpec type for use with +// apply. +func EndpointResourceSpec() *EndpointResourceSpecApplyConfiguration { + return &EndpointResourceSpecApplyConfiguration{} +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *EndpointResourceSpecApplyConfiguration) WithDescription(value string) *EndpointResourceSpecApplyConfiguration { + b.Description = &value + return b +} + +// WithEnabled sets the Enabled field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Enabled field is set to the value of the last call. +func (b *EndpointResourceSpecApplyConfiguration) WithEnabled(value bool) *EndpointResourceSpecApplyConfiguration { + b.Enabled = &value + return b +} + +// WithInterface sets the Interface field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Interface field is set to the value of the last call. +func (b *EndpointResourceSpecApplyConfiguration) WithInterface(value string) *EndpointResourceSpecApplyConfiguration { + b.Interface = &value + return b +} + +// WithURL sets the URL field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the URL field is set to the value of the last call. +func (b *EndpointResourceSpecApplyConfiguration) WithURL(value string) *EndpointResourceSpecApplyConfiguration { + b.URL = &value + return b +} + +// WithServiceRef sets the ServiceRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServiceRef field is set to the value of the last call. +func (b *EndpointResourceSpecApplyConfiguration) WithServiceRef(value apiv1alpha1.KubernetesNameRef) *EndpointResourceSpecApplyConfiguration { + b.ServiceRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/endpointresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/endpointresourcestatus.go new file mode 100644 index 000000000..54a98b5a7 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/endpointresourcestatus.go @@ -0,0 +1,75 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// EndpointResourceStatusApplyConfiguration represents a declarative configuration of the EndpointResourceStatus type for use +// with apply. +type EndpointResourceStatusApplyConfiguration struct { + Description *string `json:"description,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Interface *string `json:"interface,omitempty"` + URL *string `json:"url,omitempty"` + ServiceID *string `json:"serviceID,omitempty"` +} + +// EndpointResourceStatusApplyConfiguration constructs a declarative configuration of the EndpointResourceStatus type for use with +// apply. +func EndpointResourceStatus() *EndpointResourceStatusApplyConfiguration { + return &EndpointResourceStatusApplyConfiguration{} +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *EndpointResourceStatusApplyConfiguration) WithDescription(value string) *EndpointResourceStatusApplyConfiguration { + b.Description = &value + return b +} + +// WithEnabled sets the Enabled field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Enabled field is set to the value of the last call. +func (b *EndpointResourceStatusApplyConfiguration) WithEnabled(value bool) *EndpointResourceStatusApplyConfiguration { + b.Enabled = &value + return b +} + +// WithInterface sets the Interface field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Interface field is set to the value of the last call. +func (b *EndpointResourceStatusApplyConfiguration) WithInterface(value string) *EndpointResourceStatusApplyConfiguration { + b.Interface = &value + return b +} + +// WithURL sets the URL field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the URL field is set to the value of the last call. +func (b *EndpointResourceStatusApplyConfiguration) WithURL(value string) *EndpointResourceStatusApplyConfiguration { + b.URL = &value + return b +} + +// WithServiceID sets the ServiceID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServiceID field is set to the value of the last call. +func (b *EndpointResourceStatusApplyConfiguration) WithServiceID(value string) *EndpointResourceStatusApplyConfiguration { + b.ServiceID = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/endpointspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/endpointspec.go new file mode 100644 index 000000000..ddde864fe --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/endpointspec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EndpointSpecApplyConfiguration represents a declarative configuration of the EndpointSpec type for use +// with apply. +type EndpointSpecApplyConfiguration struct { + Import *EndpointImportApplyConfiguration `json:"import,omitempty"` + Resource *EndpointResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// EndpointSpecApplyConfiguration constructs a declarative configuration of the EndpointSpec type for use with +// apply. +func EndpointSpec() *EndpointSpecApplyConfiguration { + return &EndpointSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *EndpointSpecApplyConfiguration) WithImport(value *EndpointImportApplyConfiguration) *EndpointSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *EndpointSpecApplyConfiguration) WithResource(value *EndpointResourceSpecApplyConfiguration) *EndpointSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *EndpointSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *EndpointSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *EndpointSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *EndpointSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *EndpointSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *EndpointSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *EndpointSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *EndpointSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/endpointstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/endpointstatus.go new file mode 100644 index 000000000..63156d676 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/endpointstatus.go @@ -0,0 +1,76 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// EndpointStatusApplyConfiguration represents a declarative configuration of the EndpointStatus type for use +// with apply. +type EndpointStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *EndpointResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// EndpointStatusApplyConfiguration constructs a declarative configuration of the EndpointStatus type for use with +// apply. +func EndpointStatus() *EndpointStatusApplyConfiguration { + return &EndpointStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *EndpointStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *EndpointStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *EndpointStatusApplyConfiguration) WithID(value string) *EndpointStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *EndpointStatusApplyConfiguration) WithResource(value *EndpointResourceStatusApplyConfiguration) *EndpointStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *EndpointStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *EndpointStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/externalgateway.go b/pkg/clients/applyconfiguration/api/v1alpha1/externalgateway.go index d16d8f6b5..304964005 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/externalgateway.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/externalgateway.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/externalgatewaystatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/externalgatewaystatus.go index a93eaaab1..3b07be9fd 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/externalgatewaystatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/externalgatewaystatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/filterbykeystonetags.go b/pkg/clients/applyconfiguration/api/v1alpha1/filterbykeystonetags.go index bc4fe7536..925726e12 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/filterbykeystonetags.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/filterbykeystonetags.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/filterbyneutrontags.go b/pkg/clients/applyconfiguration/api/v1alpha1/filterbyneutrontags.go index 785486a6f..c8796fafd 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/filterbyneutrontags.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/filterbyneutrontags.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/filterbyservertags.go b/pkg/clients/applyconfiguration/api/v1alpha1/filterbyservertags.go index e8e8b6347..a7360cde9 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/filterbyservertags.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/filterbyservertags.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/fixedipstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/fixedipstatus.go index f12c972b2..88afdedf4 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/fixedipstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/fixedipstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavor.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavor.go index b6c7a5a4c..da6e101b2 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/flavor.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavor.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorextraspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorextraspec.go new file mode 100644 index 000000000..042cc0455 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorextraspec.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// FlavorExtraSpecApplyConfiguration represents a declarative configuration of the FlavorExtraSpec type for use +// with apply. +type FlavorExtraSpecApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Value *string `json:"value,omitempty"` +} + +// FlavorExtraSpecApplyConfiguration constructs a declarative configuration of the FlavorExtraSpec type for use with +// apply. +func FlavorExtraSpec() *FlavorExtraSpecApplyConfiguration { + return &FlavorExtraSpecApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *FlavorExtraSpecApplyConfiguration) WithName(value string) *FlavorExtraSpecApplyConfiguration { + b.Name = &value + return b +} + +// WithValue sets the Value field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Value field is set to the value of the last call. +func (b *FlavorExtraSpecApplyConfiguration) WithValue(value string) *FlavorExtraSpecApplyConfiguration { + b.Value = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorextraspecstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorextraspecstatus.go new file mode 100644 index 000000000..6fabec4a5 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorextraspecstatus.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// FlavorExtraSpecStatusApplyConfiguration represents a declarative configuration of the FlavorExtraSpecStatus type for use +// with apply. +type FlavorExtraSpecStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Value *string `json:"value,omitempty"` +} + +// FlavorExtraSpecStatusApplyConfiguration constructs a declarative configuration of the FlavorExtraSpecStatus type for use with +// apply. +func FlavorExtraSpecStatus() *FlavorExtraSpecStatusApplyConfiguration { + return &FlavorExtraSpecStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *FlavorExtraSpecStatusApplyConfiguration) WithName(value string) *FlavorExtraSpecStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithValue sets the Value field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Value field is set to the value of the last call. +func (b *FlavorExtraSpecStatusApplyConfiguration) WithValue(value string) *FlavorExtraSpecStatusApplyConfiguration { + b.Value = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorfilter.go index 90864da00..84ea15f96 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/flavorfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorimport.go index 8c9f5931b..a8e657fc0 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/flavorimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go index 6f3321810..28721f084 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,14 +25,16 @@ import ( // FlavorResourceSpecApplyConfiguration represents a declarative configuration of the FlavorResourceSpec type for use // with apply. type FlavorResourceSpecApplyConfiguration struct { - Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - RAM *int32 `json:"ram,omitempty"` - Vcpus *int32 `json:"vcpus,omitempty"` - Disk *int32 `json:"disk,omitempty"` - Swap *int32 `json:"swap,omitempty"` - IsPublic *bool `json:"isPublic,omitempty"` - Ephemeral *int32 `json:"ephemeral,omitempty"` + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + ID *string `json:"id,omitempty"` + Description *string `json:"description,omitempty"` + RAM *int32 `json:"ram,omitempty"` + Vcpus *int32 `json:"vcpus,omitempty"` + Disk *int32 `json:"disk,omitempty"` + Swap *int32 `json:"swap,omitempty"` + ExtraSpecs []FlavorExtraSpecApplyConfiguration `json:"extraSpecs,omitempty"` + IsPublic *bool `json:"isPublic,omitempty"` + Ephemeral *int32 `json:"ephemeral,omitempty"` } // FlavorResourceSpecApplyConfiguration constructs a declarative configuration of the FlavorResourceSpec type for use with @@ -49,6 +51,14 @@ func (b *FlavorResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenSt return b } +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *FlavorResourceSpecApplyConfiguration) WithID(value string) *FlavorResourceSpecApplyConfiguration { + b.ID = &value + return b +} + // WithDescription sets the Description field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Description field is set to the value of the last call. @@ -89,6 +99,19 @@ func (b *FlavorResourceSpecApplyConfiguration) WithSwap(value int32) *FlavorReso return b } +// WithExtraSpecs adds the given value to the ExtraSpecs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the ExtraSpecs field. +func (b *FlavorResourceSpecApplyConfiguration) WithExtraSpecs(values ...*FlavorExtraSpecApplyConfiguration) *FlavorResourceSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithExtraSpecs") + } + b.ExtraSpecs = append(b.ExtraSpecs, *values[i]) + } + return b +} + // WithIsPublic sets the IsPublic field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the IsPublic field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcestatus.go index 28ab52d58..ac47f6311 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,14 +21,15 @@ package v1alpha1 // FlavorResourceStatusApplyConfiguration represents a declarative configuration of the FlavorResourceStatus type for use // with apply. type FlavorResourceStatusApplyConfiguration struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - RAM *int32 `json:"ram,omitempty"` - Vcpus *int32 `json:"vcpus,omitempty"` - Disk *int32 `json:"disk,omitempty"` - Swap *int32 `json:"swap,omitempty"` - IsPublic *bool `json:"isPublic,omitempty"` - Ephemeral *int32 `json:"ephemeral,omitempty"` + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + RAM *int32 `json:"ram,omitempty"` + Vcpus *int32 `json:"vcpus,omitempty"` + Disk *int32 `json:"disk,omitempty"` + Swap *int32 `json:"swap,omitempty"` + ExtraSpecs []FlavorExtraSpecStatusApplyConfiguration `json:"extraSpecs,omitempty"` + IsPublic *bool `json:"isPublic,omitempty"` + Ephemeral *int32 `json:"ephemeral,omitempty"` } // FlavorResourceStatusApplyConfiguration constructs a declarative configuration of the FlavorResourceStatus type for use with @@ -85,6 +86,19 @@ func (b *FlavorResourceStatusApplyConfiguration) WithSwap(value int32) *FlavorRe return b } +// WithExtraSpecs adds the given value to the ExtraSpecs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the ExtraSpecs field. +func (b *FlavorResourceStatusApplyConfiguration) WithExtraSpecs(values ...*FlavorExtraSpecStatusApplyConfiguration) *FlavorResourceStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithExtraSpecs") + } + b.ExtraSpecs = append(b.ExtraSpecs, *values[i]) + } + return b +} + // WithIsPublic sets the IsPublic field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the IsPublic field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorspec.go index f60351b00..28f5e9f50 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/flavorspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // FlavorSpecApplyConfiguration represents a declarative configuration of the FlavorSpec type for use @@ -29,6 +30,7 @@ type FlavorSpecApplyConfiguration struct { Resource *FlavorResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *FlavorSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsA return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *FlavorSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *FlavorSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/flavorstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/flavorstatus.go index 660532d5d..dd370aa1b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/flavorstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/flavorstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // FlavorStatusApplyConfiguration represents a declarative configuration of the FlavorStatus type for use // with apply. type FlavorStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *FlavorResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *FlavorResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // FlavorStatusApplyConfiguration constructs a declarative configuration of the FlavorStatus type for use with @@ -64,3 +66,11 @@ func (b *FlavorStatusApplyConfiguration) WithResource(value *FlavorResourceStatu b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *FlavorStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *FlavorStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/floatingip.go b/pkg/clients/applyconfiguration/api/v1alpha1/floatingip.go index 29c0ddd81..2923fc5df 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/floatingip.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/floatingip.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipfilter.go index 518de3eb0..bdaf24e7a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipimport.go index 261d3b3d7..759a0a4b3 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcespec.go index 11b4cb473..7de2cc0ef 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcestatus.go index c3c792fb2..697f5ba19 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipspec.go index 3a34d0527..066b710b8 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // FloatingIPSpecApplyConfiguration represents a declarative configuration of the FloatingIPSpec type for use @@ -29,6 +30,7 @@ type FloatingIPSpecApplyConfiguration struct { Resource *FloatingIPResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *FloatingIPSpecApplyConfiguration) WithManagedOptions(value *ManagedOpti return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *FloatingIPSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *FloatingIPSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipstatus.go index c78821748..eb856b839 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/floatingipstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/floatingipstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // FloatingIPStatusApplyConfiguration represents a declarative configuration of the FloatingIPStatus type for use // with apply. type FloatingIPStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *FloatingIPResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *FloatingIPResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // FloatingIPStatusApplyConfiguration constructs a declarative configuration of the FloatingIPStatus type for use with @@ -64,3 +66,11 @@ func (b *FloatingIPStatusApplyConfiguration) WithResource(value *FloatingIPResou b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *FloatingIPStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *FloatingIPStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/group.go b/pkg/clients/applyconfiguration/api/v1alpha1/group.go index c01e53c37..1904aa4f2 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/group.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/group.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/groupfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/groupfilter.go index 74e576e8f..974125061 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/groupfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/groupfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/groupimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/groupimport.go index 8b2722827..f5ea5aaff 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/groupimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/groupimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcespec.go index 1be73b8ad..3d914a439 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcestatus.go index 53f2fd0ab..bfe2aa55f 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/groupresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/groupspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/groupspec.go index 0aaee9e04..218db914f 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/groupspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/groupspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // GroupSpecApplyConfiguration represents a declarative configuration of the GroupSpec type for use @@ -29,6 +30,7 @@ type GroupSpecApplyConfiguration struct { Resource *GroupResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *GroupSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsAp return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *GroupSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *GroupSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/groupstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/groupstatus.go index 88af39d51..c7f97fef2 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/groupstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/groupstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // GroupStatusApplyConfiguration represents a declarative configuration of the GroupStatus type for use // with apply. type GroupStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *GroupResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *GroupResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // GroupStatusApplyConfiguration constructs a declarative configuration of the GroupStatus type for use with @@ -64,3 +66,11 @@ func (b *GroupStatusApplyConfiguration) WithResource(value *GroupResourceStatusA b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *GroupStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *GroupStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/hostid.go b/pkg/clients/applyconfiguration/api/v1alpha1/hostid.go new file mode 100644 index 000000000..3f571fe0b --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/hostid.go @@ -0,0 +1,52 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// HostIDApplyConfiguration represents a declarative configuration of the HostID type for use +// with apply. +type HostIDApplyConfiguration struct { + ID *string `json:"id,omitempty"` + ServerRef *apiv1alpha1.KubernetesNameRef `json:"serverRef,omitempty"` +} + +// HostIDApplyConfiguration constructs a declarative configuration of the HostID type for use with +// apply. +func HostID() *HostIDApplyConfiguration { + return &HostIDApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *HostIDApplyConfiguration) WithID(value string) *HostIDApplyConfiguration { + b.ID = &value + return b +} + +// WithServerRef sets the ServerRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServerRef field is set to the value of the last call. +func (b *HostIDApplyConfiguration) WithServerRef(value apiv1alpha1.KubernetesNameRef) *HostIDApplyConfiguration { + b.ServerRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/hostroute.go b/pkg/clients/applyconfiguration/api/v1alpha1/hostroute.go index 19be79bac..4cc09b094 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/hostroute.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/hostroute.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/hostroutestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/hostroutestatus.go index 90bfffa3d..11bf6a596 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/hostroutestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/hostroutestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/image.go b/pkg/clients/applyconfiguration/api/v1alpha1/image.go index 9a3d2d392..386817976 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/image.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/image.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagecontent.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagecontent.go index 6b096f15a..d9e68e2e6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagecontent.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagecontent.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagecontentsourcedownload.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagecontentsourcedownload.go index 9ed05d174..b00f1c48d 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagecontentsourcedownload.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagecontentsourcedownload.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagefilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagefilter.go index 3d6a9bb2b..827d8c797 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagefilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagefilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagehash.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagehash.go index 5c8558384..67a0478d3 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagehash.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagehash.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imageimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/imageimport.go index bcf5fa561..27df0f019 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imageimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imageimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imageproperties.go b/pkg/clients/applyconfiguration/api/v1alpha1/imageproperties.go index 36265de38..f73ac4121 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imageproperties.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imageproperties.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertieshardware.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertieshardware.go index 926a0c247..2d7f89208 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertieshardware.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertieshardware.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertiesoperatingsystem.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertiesoperatingsystem.go index fa1789a4d..81f6858de 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertiesoperatingsystem.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagepropertiesoperatingsystem.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcespec.go index aff932b2b..5c1adb6ad 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcestatus.go index bc5c5db70..e697b64d0 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imageresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagespec.go index ba1ea2252..e63cfdbce 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // ImageSpecApplyConfiguration represents a declarative configuration of the ImageSpec type for use @@ -29,6 +30,7 @@ type ImageSpecApplyConfiguration struct { Resource *ImageResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *ImageSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsAp return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *ImageSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *ImageSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go index 15c7410b9..0a4ba2519 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) @@ -28,6 +29,7 @@ type ImageStatusApplyConfiguration struct { Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` ID *string `json:"id,omitempty"` Resource *ImageResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` ImageStatusExtraApplyConfiguration `json:",inline"` } @@ -66,6 +68,14 @@ func (b *ImageStatusApplyConfiguration) WithResource(value *ImageResourceStatusA return b } +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *ImageStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *ImageStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} + // WithDownloadAttempts sets the DownloadAttempts field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the DownloadAttempts field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go b/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go index e5a147d2b..d2fc95947 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/imagestatusextra.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/ipv6options.go b/pkg/clients/applyconfiguration/api/v1alpha1/ipv6options.go index a82b36222..d95b64185 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/ipv6options.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/ipv6options.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/keypair.go b/pkg/clients/applyconfiguration/api/v1alpha1/keypair.go index db29ba7ba..9a5937b2b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/keypair.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/keypair.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/keypairfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/keypairfilter.go index 22f0353bf..bee0e363b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/keypairfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/keypairfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/keypairimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/keypairimport.go index ed766367b..14a0205b9 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/keypairimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/keypairimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcespec.go index 1ae0c8fe9..fc2069cfa 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcestatus.go index 2be862ba2..f0047e4c1 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/keypairresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/keypairspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/keypairspec.go index ffe67fe9c..e8c3e5e21 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/keypairspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/keypairspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // KeyPairSpecApplyConfiguration represents a declarative configuration of the KeyPairSpec type for use @@ -29,6 +30,7 @@ type KeyPairSpecApplyConfiguration struct { Resource *KeyPairResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *KeyPairSpecApplyConfiguration) WithManagedOptions(value *ManagedOptions return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *KeyPairSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *KeyPairSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/keypairstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/keypairstatus.go index 5a4a51b13..591a9a77b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/keypairstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/keypairstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // KeyPairStatusApplyConfiguration represents a declarative configuration of the KeyPairStatus type for use // with apply. type KeyPairStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *KeyPairResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *KeyPairResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // KeyPairStatusApplyConfiguration constructs a declarative configuration of the KeyPairStatus type for use with @@ -64,3 +66,11 @@ func (b *KeyPairStatusApplyConfiguration) WithResource(value *KeyPairResourceSta b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *KeyPairStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *KeyPairStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/managedoptions.go b/pkg/clients/applyconfiguration/api/v1alpha1/managedoptions.go index 89f690a9c..092ab7883 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/managedoptions.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/managedoptions.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/network.go b/pkg/clients/applyconfiguration/api/v1alpha1/network.go index f8bac102e..76876d253 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/network.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/network.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/networkfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/networkfilter.go index f1a1d5f87..557babf8b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/networkfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/networkfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/networkimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/networkimport.go index fa9f7702e..f0e6311cf 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/networkimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/networkimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcespec.go index 8646ab92f..a85d19867 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcestatus.go index 1935b223b..fa1d0a2e5 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/networkresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/networkspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/networkspec.go index 8de986799..682a2b264 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/networkspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/networkspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // NetworkSpecApplyConfiguration represents a declarative configuration of the NetworkSpec type for use @@ -29,6 +30,7 @@ type NetworkSpecApplyConfiguration struct { Resource *NetworkResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *NetworkSpecApplyConfiguration) WithManagedOptions(value *ManagedOptions return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *NetworkSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *NetworkSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/networkstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/networkstatus.go index 1c8312a59..fa0fa85ec 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/networkstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/networkstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // NetworkStatusApplyConfiguration represents a declarative configuration of the NetworkStatus type for use // with apply. type NetworkStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *NetworkResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *NetworkResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // NetworkStatusApplyConfiguration constructs a declarative configuration of the NetworkStatus type for use with @@ -64,3 +66,11 @@ func (b *NetworkStatusApplyConfiguration) WithResource(value *NetworkResourceSta b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *NetworkStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *NetworkStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/neutronstatusmetadata.go b/pkg/clients/applyconfiguration/api/v1alpha1/neutronstatusmetadata.go index b9cc4fd26..04d7aca93 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/neutronstatusmetadata.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/neutronstatusmetadata.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/port.go b/pkg/clients/applyconfiguration/api/v1alpha1/port.go index 2ef3698b9..17b2763e5 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/port.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/port.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/portfilter.go index e1732f652..2db6c09a6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ type PortFilterApplyConfiguration struct { NetworkRef *apiv1alpha1.KubernetesNameRef `json:"networkRef,omitempty"` ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` AdminStateUp *bool `json:"adminStateUp,omitempty"` + MACAddress *string `json:"macAddress,omitempty"` FilterByNeutronTagsApplyConfiguration `json:",inline"` } @@ -79,6 +80,14 @@ func (b *PortFilterApplyConfiguration) WithAdminStateUp(value bool) *PortFilterA return b } +// WithMACAddress sets the MACAddress field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MACAddress field is set to the value of the last call. +func (b *PortFilterApplyConfiguration) WithMACAddress(value string) *PortFilterApplyConfiguration { + b.MACAddress = &value + return b +} + // WithTags adds the given value to the Tags field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Tags field. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/portimport.go index 272da1940..fd760ff61 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portrangespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/portrangespec.go index 811b56f0e..64bc4a298 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portrangespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portrangespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portrangestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/portrangestatus.go index 4728e5ca0..b92bd01c6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portrangestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portrangestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go index 67351b05c..e0935b42c 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,17 +25,22 @@ import ( // PortResourceSpecApplyConfiguration represents a declarative configuration of the PortResourceSpec type for use // with apply. type PortResourceSpecApplyConfiguration struct { - Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` - Description *apiv1alpha1.NeutronDescription `json:"description,omitempty"` - NetworkRef *apiv1alpha1.KubernetesNameRef `json:"networkRef,omitempty"` - Tags []apiv1alpha1.NeutronTag `json:"tags,omitempty"` - AllowedAddressPairs []AllowedAddressPairApplyConfiguration `json:"allowedAddressPairs,omitempty"` - Addresses []AddressApplyConfiguration `json:"addresses,omitempty"` - AdminStateUp *bool `json:"adminStateUp,omitempty"` - SecurityGroupRefs []apiv1alpha1.OpenStackName `json:"securityGroupRefs,omitempty"` - VNICType *string `json:"vnicType,omitempty"` - PortSecurity *apiv1alpha1.PortSecurityState `json:"portSecurity,omitempty"` - ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *apiv1alpha1.NeutronDescription `json:"description,omitempty"` + NetworkRef *apiv1alpha1.KubernetesNameRef `json:"networkRef,omitempty"` + Tags []apiv1alpha1.NeutronTag `json:"tags,omitempty"` + AllowedAddressPairs []AllowedAddressPairApplyConfiguration `json:"allowedAddressPairs,omitempty"` + Addresses []AddressApplyConfiguration `json:"addresses,omitempty"` + AdminStateUp *bool `json:"adminStateUp,omitempty"` + SecurityGroupRefs []apiv1alpha1.KubernetesNameRef `json:"securityGroupRefs,omitempty"` + VNICType *string `json:"vnicType,omitempty"` + PortSecurity *apiv1alpha1.PortSecurityState `json:"portSecurity,omitempty"` + ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + MACAddress *string `json:"macAddress,omitempty"` + HostID *HostIDApplyConfiguration `json:"hostID,omitempty"` + TrustedVIF *bool `json:"trustedVIF,omitempty"` + ValueSpecs []PortValueSpecApplyConfiguration `json:"valueSpecs,omitempty"` + PropagateUplinkStatus *bool `json:"propagateUplinkStatus,omitempty"` } // PortResourceSpecApplyConfiguration constructs a declarative configuration of the PortResourceSpec type for use with @@ -115,7 +120,7 @@ func (b *PortResourceSpecApplyConfiguration) WithAdminStateUp(value bool) *PortR // WithSecurityGroupRefs adds the given value to the SecurityGroupRefs field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the SecurityGroupRefs field. -func (b *PortResourceSpecApplyConfiguration) WithSecurityGroupRefs(values ...apiv1alpha1.OpenStackName) *PortResourceSpecApplyConfiguration { +func (b *PortResourceSpecApplyConfiguration) WithSecurityGroupRefs(values ...apiv1alpha1.KubernetesNameRef) *PortResourceSpecApplyConfiguration { for i := range values { b.SecurityGroupRefs = append(b.SecurityGroupRefs, values[i]) } @@ -145,3 +150,48 @@ func (b *PortResourceSpecApplyConfiguration) WithProjectRef(value apiv1alpha1.Ku b.ProjectRef = &value return b } + +// WithMACAddress sets the MACAddress field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MACAddress field is set to the value of the last call. +func (b *PortResourceSpecApplyConfiguration) WithMACAddress(value string) *PortResourceSpecApplyConfiguration { + b.MACAddress = &value + return b +} + +// WithHostID sets the HostID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the HostID field is set to the value of the last call. +func (b *PortResourceSpecApplyConfiguration) WithHostID(value *HostIDApplyConfiguration) *PortResourceSpecApplyConfiguration { + b.HostID = value + return b +} + +// WithTrustedVIF sets the TrustedVIF field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the TrustedVIF field is set to the value of the last call. +func (b *PortResourceSpecApplyConfiguration) WithTrustedVIF(value bool) *PortResourceSpecApplyConfiguration { + b.TrustedVIF = &value + return b +} + +// WithValueSpecs adds the given value to the ValueSpecs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the ValueSpecs field. +func (b *PortResourceSpecApplyConfiguration) WithValueSpecs(values ...*PortValueSpecApplyConfiguration) *PortResourceSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithValueSpecs") + } + b.ValueSpecs = append(b.ValueSpecs, *values[i]) + } + return b +} + +// WithPropagateUplinkStatus sets the PropagateUplinkStatus field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PropagateUplinkStatus field is set to the value of the last call. +func (b *PortResourceSpecApplyConfiguration) WithPropagateUplinkStatus(value bool) *PortResourceSpecApplyConfiguration { + b.PropagateUplinkStatus = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/portresourcestatus.go index 1fd734822..6557cb5a2 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -41,6 +41,8 @@ type PortResourceStatusApplyConfiguration struct { PropagateUplinkStatus *bool `json:"propagateUplinkStatus,omitempty"` VNICType *string `json:"vnicType,omitempty"` PortSecurityEnabled *bool `json:"portSecurityEnabled,omitempty"` + HostID *string `json:"hostID,omitempty"` + TrustedVIF *bool `json:"trustedVIF,omitempty"` NeutronStatusMetadataApplyConfiguration `json:",inline"` } @@ -192,6 +194,22 @@ func (b *PortResourceStatusApplyConfiguration) WithPortSecurityEnabled(value boo return b } +// WithHostID sets the HostID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the HostID field is set to the value of the last call. +func (b *PortResourceStatusApplyConfiguration) WithHostID(value string) *PortResourceStatusApplyConfiguration { + b.HostID = &value + return b +} + +// WithTrustedVIF sets the TrustedVIF field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the TrustedVIF field is set to the value of the last call. +func (b *PortResourceStatusApplyConfiguration) WithTrustedVIF(value bool) *PortResourceStatusApplyConfiguration { + b.TrustedVIF = &value + return b +} + // WithCreatedAt sets the CreatedAt field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CreatedAt field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/portspec.go index 6b6a549f2..15f08e7b0 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // PortSpecApplyConfiguration represents a declarative configuration of the PortSpec type for use @@ -29,6 +30,7 @@ type PortSpecApplyConfiguration struct { Resource *PortResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *PortSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApp return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *PortSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *PortSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/portstatus.go index 700231629..7fe027d83 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/portstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // PortStatusApplyConfiguration represents a declarative configuration of the PortStatus type for use // with apply. type PortStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *PortResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *PortResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // PortStatusApplyConfiguration constructs a declarative configuration of the PortStatus type for use with @@ -64,3 +66,11 @@ func (b *PortStatusApplyConfiguration) WithResource(value *PortResourceStatusApp b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *PortStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *PortStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/portvaluespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/portvaluespec.go new file mode 100644 index 000000000..c4d305192 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/portvaluespec.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// PortValueSpecApplyConfiguration represents a declarative configuration of the PortValueSpec type for use +// with apply. +type PortValueSpecApplyConfiguration struct { + Key *string `json:"key,omitempty"` + Value *string `json:"value,omitempty"` +} + +// PortValueSpecApplyConfiguration constructs a declarative configuration of the PortValueSpec type for use with +// apply. +func PortValueSpec() *PortValueSpecApplyConfiguration { + return &PortValueSpecApplyConfiguration{} +} + +// WithKey sets the Key field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Key field is set to the value of the last call. +func (b *PortValueSpecApplyConfiguration) WithKey(value string) *PortValueSpecApplyConfiguration { + b.Key = &value + return b +} + +// WithValue sets the Value field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Value field is set to the value of the last call. +func (b *PortValueSpecApplyConfiguration) WithValue(value string) *PortValueSpecApplyConfiguration { + b.Value = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/project.go b/pkg/clients/applyconfiguration/api/v1alpha1/project.go index 7bb0dc9a6..4ce5d897a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/project.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/project.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/projectfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/projectfilter.go index 0bdcf6a82..f7538e1c1 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/projectfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/projectfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,8 @@ import ( // ProjectFilterApplyConfiguration represents a declarative configuration of the ProjectFilter type for use // with apply. type ProjectFilterApplyConfiguration struct { - Name *apiv1alpha1.KeystoneName `json:"name,omitempty"` + Name *apiv1alpha1.KeystoneName `json:"name,omitempty"` + DomainRef *apiv1alpha1.KubernetesNameRef `json:"domainRef,omitempty"` FilterByKeystoneTagsApplyConfiguration `json:",inline"` } @@ -43,6 +44,14 @@ func (b *ProjectFilterApplyConfiguration) WithName(value apiv1alpha1.KeystoneNam return b } +// WithDomainRef sets the DomainRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainRef field is set to the value of the last call. +func (b *ProjectFilterApplyConfiguration) WithDomainRef(value apiv1alpha1.KubernetesNameRef) *ProjectFilterApplyConfiguration { + b.DomainRef = &value + return b +} + // WithTags adds the given value to the Tags field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Tags field. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/projectimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/projectimport.go index 395deb31f..486e72fd5 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/projectimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/projectimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcespec.go index fc8721b8c..0d49ae3ae 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,10 +25,11 @@ import ( // ProjectResourceSpecApplyConfiguration represents a declarative configuration of the ProjectResourceSpec type for use // with apply. type ProjectResourceSpecApplyConfiguration struct { - Name *apiv1alpha1.KeystoneName `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Tags []apiv1alpha1.KeystoneTag `json:"tags,omitempty"` + Name *apiv1alpha1.KeystoneName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + DomainRef *apiv1alpha1.KubernetesNameRef `json:"domainRef,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Tags []apiv1alpha1.KeystoneTag `json:"tags,omitempty"` } // ProjectResourceSpecApplyConfiguration constructs a declarative configuration of the ProjectResourceSpec type for use with @@ -53,6 +54,14 @@ func (b *ProjectResourceSpecApplyConfiguration) WithDescription(value string) *P return b } +// WithDomainRef sets the DomainRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainRef field is set to the value of the last call. +func (b *ProjectResourceSpecApplyConfiguration) WithDomainRef(value apiv1alpha1.KubernetesNameRef) *ProjectResourceSpecApplyConfiguration { + b.DomainRef = &value + return b +} + // WithEnabled sets the Enabled field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Enabled field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcestatus.go index 5520405c9..4a7fdb3cc 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/projectresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ package v1alpha1 type ProjectResourceStatusApplyConfiguration struct { Name *string `json:"name,omitempty"` Description *string `json:"description,omitempty"` + DomainID *string `json:"domainID,omitempty"` Enabled *bool `json:"enabled,omitempty"` Tags []string `json:"tags,omitempty"` } @@ -49,6 +50,14 @@ func (b *ProjectResourceStatusApplyConfiguration) WithDescription(value string) return b } +// WithDomainID sets the DomainID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainID field is set to the value of the last call. +func (b *ProjectResourceStatusApplyConfiguration) WithDomainID(value string) *ProjectResourceStatusApplyConfiguration { + b.DomainID = &value + return b +} + // WithEnabled sets the Enabled field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Enabled field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/projectspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/projectspec.go index d98c9dc9c..b9a681c7d 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/projectspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/projectspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // ProjectSpecApplyConfiguration represents a declarative configuration of the ProjectSpec type for use @@ -29,6 +30,7 @@ type ProjectSpecApplyConfiguration struct { Resource *ProjectResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *ProjectSpecApplyConfiguration) WithManagedOptions(value *ManagedOptions return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *ProjectSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *ProjectSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/projectstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/projectstatus.go index f829757ae..469f29ea4 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/projectstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/projectstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // ProjectStatusApplyConfiguration represents a declarative configuration of the ProjectStatus type for use // with apply. type ProjectStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *ProjectResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *ProjectResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // ProjectStatusApplyConfiguration constructs a declarative configuration of the ProjectStatus type for use with @@ -64,3 +66,11 @@ func (b *ProjectStatusApplyConfiguration) WithResource(value *ProjectResourceSta b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *ProjectStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *ProjectStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/providerpropertiesstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/providerpropertiesstatus.go index a274c3f3b..47bfc8c2a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/providerpropertiesstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/providerpropertiesstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/role.go b/pkg/clients/applyconfiguration/api/v1alpha1/role.go index 14fcda794..1fcf9bf44 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/role.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/role.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleassignment.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignment.go new file mode 100644 index 000000000..26462d14d --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignment.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// RoleAssignmentApplyConfiguration represents a declarative configuration of the RoleAssignment type for use +// with apply. +type RoleAssignmentApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *RoleAssignmentSpecApplyConfiguration `json:"spec,omitempty"` + Status *RoleAssignmentStatusApplyConfiguration `json:"status,omitempty"` +} + +// RoleAssignment constructs a declarative configuration of the RoleAssignment type for use with +// apply. +func RoleAssignment(name, namespace string) *RoleAssignmentApplyConfiguration { + b := &RoleAssignmentApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("RoleAssignment") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractRoleAssignment extracts the applied configuration owned by fieldManager from +// roleAssignment. If no managedFields are found in roleAssignment for fieldManager, a +// RoleAssignmentApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// roleAssignment must be a unmodified RoleAssignment API object that was retrieved from the Kubernetes API. +// ExtractRoleAssignment provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractRoleAssignment(roleAssignment *apiv1alpha1.RoleAssignment, fieldManager string) (*RoleAssignmentApplyConfiguration, error) { + return extractRoleAssignment(roleAssignment, fieldManager, "") +} + +// ExtractRoleAssignmentStatus is the same as ExtractRoleAssignment except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractRoleAssignmentStatus(roleAssignment *apiv1alpha1.RoleAssignment, fieldManager string) (*RoleAssignmentApplyConfiguration, error) { + return extractRoleAssignment(roleAssignment, fieldManager, "status") +} + +func extractRoleAssignment(roleAssignment *apiv1alpha1.RoleAssignment, fieldManager string, subresource string) (*RoleAssignmentApplyConfiguration, error) { + b := &RoleAssignmentApplyConfiguration{} + err := managedfields.ExtractInto(roleAssignment, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignment"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(roleAssignment.Name) + b.WithNamespace(roleAssignment.Namespace) + + b.WithKind("RoleAssignment") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b RoleAssignmentApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithKind(value string) *RoleAssignmentApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithAPIVersion(value string) *RoleAssignmentApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithName(value string) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithGenerateName(value string) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithNamespace(value string) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithUID(value types.UID) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithResourceVersion(value string) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithGeneration(value int64) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithCreationTimestamp(value metav1.Time) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *RoleAssignmentApplyConfiguration) WithLabels(entries map[string]string) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *RoleAssignmentApplyConfiguration) WithAnnotations(entries map[string]string) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *RoleAssignmentApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *RoleAssignmentApplyConfiguration) WithFinalizers(values ...string) *RoleAssignmentApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *RoleAssignmentApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithSpec(value *RoleAssignmentSpecApplyConfiguration) *RoleAssignmentApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *RoleAssignmentApplyConfiguration) WithStatus(value *RoleAssignmentStatusApplyConfiguration) *RoleAssignmentApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *RoleAssignmentApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *RoleAssignmentApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *RoleAssignmentApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *RoleAssignmentApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentfilter.go new file mode 100644 index 000000000..5367d30da --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentfilter.go @@ -0,0 +1,79 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// RoleAssignmentFilterApplyConfiguration represents a declarative configuration of the RoleAssignmentFilter type for use +// with apply. +type RoleAssignmentFilterApplyConfiguration struct { + RoleRef *apiv1alpha1.KubernetesNameRef `json:"roleRef,omitempty"` + UserRef *apiv1alpha1.KubernetesNameRef `json:"userRef,omitempty"` + GroupRef *apiv1alpha1.KubernetesNameRef `json:"groupRef,omitempty"` + ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + DomainRef *apiv1alpha1.KubernetesNameRef `json:"domainRef,omitempty"` +} + +// RoleAssignmentFilterApplyConfiguration constructs a declarative configuration of the RoleAssignmentFilter type for use with +// apply. +func RoleAssignmentFilter() *RoleAssignmentFilterApplyConfiguration { + return &RoleAssignmentFilterApplyConfiguration{} +} + +// WithRoleRef sets the RoleRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the RoleRef field is set to the value of the last call. +func (b *RoleAssignmentFilterApplyConfiguration) WithRoleRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentFilterApplyConfiguration { + b.RoleRef = &value + return b +} + +// WithUserRef sets the UserRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UserRef field is set to the value of the last call. +func (b *RoleAssignmentFilterApplyConfiguration) WithUserRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentFilterApplyConfiguration { + b.UserRef = &value + return b +} + +// WithGroupRef sets the GroupRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GroupRef field is set to the value of the last call. +func (b *RoleAssignmentFilterApplyConfiguration) WithGroupRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentFilterApplyConfiguration { + b.GroupRef = &value + return b +} + +// WithProjectRef sets the ProjectRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectRef field is set to the value of the last call. +func (b *RoleAssignmentFilterApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentFilterApplyConfiguration { + b.ProjectRef = &value + return b +} + +// WithDomainRef sets the DomainRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainRef field is set to the value of the last call. +func (b *RoleAssignmentFilterApplyConfiguration) WithDomainRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentFilterApplyConfiguration { + b.DomainRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentimport.go new file mode 100644 index 000000000..172fa19d9 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentimport.go @@ -0,0 +1,39 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// RoleAssignmentImportApplyConfiguration represents a declarative configuration of the RoleAssignmentImport type for use +// with apply. +type RoleAssignmentImportApplyConfiguration struct { + Filter *RoleAssignmentFilterApplyConfiguration `json:"filter,omitempty"` +} + +// RoleAssignmentImportApplyConfiguration constructs a declarative configuration of the RoleAssignmentImport type for use with +// apply. +func RoleAssignmentImport() *RoleAssignmentImportApplyConfiguration { + return &RoleAssignmentImportApplyConfiguration{} +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *RoleAssignmentImportApplyConfiguration) WithFilter(value *RoleAssignmentFilterApplyConfiguration) *RoleAssignmentImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentresourcespec.go new file mode 100644 index 000000000..680572620 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentresourcespec.go @@ -0,0 +1,79 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// RoleAssignmentResourceSpecApplyConfiguration represents a declarative configuration of the RoleAssignmentResourceSpec type for use +// with apply. +type RoleAssignmentResourceSpecApplyConfiguration struct { + RoleRef *apiv1alpha1.KubernetesNameRef `json:"roleRef,omitempty"` + UserRef *apiv1alpha1.KubernetesNameRef `json:"userRef,omitempty"` + GroupRef *apiv1alpha1.KubernetesNameRef `json:"groupRef,omitempty"` + ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + DomainRef *apiv1alpha1.KubernetesNameRef `json:"domainRef,omitempty"` +} + +// RoleAssignmentResourceSpecApplyConfiguration constructs a declarative configuration of the RoleAssignmentResourceSpec type for use with +// apply. +func RoleAssignmentResourceSpec() *RoleAssignmentResourceSpecApplyConfiguration { + return &RoleAssignmentResourceSpecApplyConfiguration{} +} + +// WithRoleRef sets the RoleRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the RoleRef field is set to the value of the last call. +func (b *RoleAssignmentResourceSpecApplyConfiguration) WithRoleRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentResourceSpecApplyConfiguration { + b.RoleRef = &value + return b +} + +// WithUserRef sets the UserRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UserRef field is set to the value of the last call. +func (b *RoleAssignmentResourceSpecApplyConfiguration) WithUserRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentResourceSpecApplyConfiguration { + b.UserRef = &value + return b +} + +// WithGroupRef sets the GroupRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GroupRef field is set to the value of the last call. +func (b *RoleAssignmentResourceSpecApplyConfiguration) WithGroupRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentResourceSpecApplyConfiguration { + b.GroupRef = &value + return b +} + +// WithProjectRef sets the ProjectRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectRef field is set to the value of the last call. +func (b *RoleAssignmentResourceSpecApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentResourceSpecApplyConfiguration { + b.ProjectRef = &value + return b +} + +// WithDomainRef sets the DomainRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainRef field is set to the value of the last call. +func (b *RoleAssignmentResourceSpecApplyConfiguration) WithDomainRef(value apiv1alpha1.KubernetesNameRef) *RoleAssignmentResourceSpecApplyConfiguration { + b.DomainRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentresourcestatus.go new file mode 100644 index 000000000..e4e29148e --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentresourcestatus.go @@ -0,0 +1,75 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// RoleAssignmentResourceStatusApplyConfiguration represents a declarative configuration of the RoleAssignmentResourceStatus type for use +// with apply. +type RoleAssignmentResourceStatusApplyConfiguration struct { + RoleID *string `json:"roleID,omitempty"` + UserID *string `json:"userID,omitempty"` + GroupID *string `json:"groupID,omitempty"` + ProjectID *string `json:"projectID,omitempty"` + DomainID *string `json:"domainID,omitempty"` +} + +// RoleAssignmentResourceStatusApplyConfiguration constructs a declarative configuration of the RoleAssignmentResourceStatus type for use with +// apply. +func RoleAssignmentResourceStatus() *RoleAssignmentResourceStatusApplyConfiguration { + return &RoleAssignmentResourceStatusApplyConfiguration{} +} + +// WithRoleID sets the RoleID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the RoleID field is set to the value of the last call. +func (b *RoleAssignmentResourceStatusApplyConfiguration) WithRoleID(value string) *RoleAssignmentResourceStatusApplyConfiguration { + b.RoleID = &value + return b +} + +// WithUserID sets the UserID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UserID field is set to the value of the last call. +func (b *RoleAssignmentResourceStatusApplyConfiguration) WithUserID(value string) *RoleAssignmentResourceStatusApplyConfiguration { + b.UserID = &value + return b +} + +// WithGroupID sets the GroupID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GroupID field is set to the value of the last call. +func (b *RoleAssignmentResourceStatusApplyConfiguration) WithGroupID(value string) *RoleAssignmentResourceStatusApplyConfiguration { + b.GroupID = &value + return b +} + +// WithProjectID sets the ProjectID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectID field is set to the value of the last call. +func (b *RoleAssignmentResourceStatusApplyConfiguration) WithProjectID(value string) *RoleAssignmentResourceStatusApplyConfiguration { + b.ProjectID = &value + return b +} + +// WithDomainID sets the DomainID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainID field is set to the value of the last call. +func (b *RoleAssignmentResourceStatusApplyConfiguration) WithDomainID(value string) *RoleAssignmentResourceStatusApplyConfiguration { + b.DomainID = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentspec.go new file mode 100644 index 000000000..6ecab3bac --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentspec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// RoleAssignmentSpecApplyConfiguration represents a declarative configuration of the RoleAssignmentSpec type for use +// with apply. +type RoleAssignmentSpecApplyConfiguration struct { + Import *RoleAssignmentImportApplyConfiguration `json:"import,omitempty"` + Resource *RoleAssignmentResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// RoleAssignmentSpecApplyConfiguration constructs a declarative configuration of the RoleAssignmentSpec type for use with +// apply. +func RoleAssignmentSpec() *RoleAssignmentSpecApplyConfiguration { + return &RoleAssignmentSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *RoleAssignmentSpecApplyConfiguration) WithImport(value *RoleAssignmentImportApplyConfiguration) *RoleAssignmentSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *RoleAssignmentSpecApplyConfiguration) WithResource(value *RoleAssignmentResourceSpecApplyConfiguration) *RoleAssignmentSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *RoleAssignmentSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *RoleAssignmentSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *RoleAssignmentSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *RoleAssignmentSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *RoleAssignmentSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *RoleAssignmentSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *RoleAssignmentSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *RoleAssignmentSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentstatus.go new file mode 100644 index 000000000..08b7d742a --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleassignmentstatus.go @@ -0,0 +1,67 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// RoleAssignmentStatusApplyConfiguration represents a declarative configuration of the RoleAssignmentStatus type for use +// with apply. +type RoleAssignmentStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + Resource *RoleAssignmentResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// RoleAssignmentStatusApplyConfiguration constructs a declarative configuration of the RoleAssignmentStatus type for use with +// apply. +func RoleAssignmentStatus() *RoleAssignmentStatusApplyConfiguration { + return &RoleAssignmentStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *RoleAssignmentStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *RoleAssignmentStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *RoleAssignmentStatusApplyConfiguration) WithResource(value *RoleAssignmentResourceStatusApplyConfiguration) *RoleAssignmentStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *RoleAssignmentStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *RoleAssignmentStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/rolefilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/rolefilter.go index d27c0d297..2194e2982 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/rolefilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/rolefilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleimport.go index da25d500b..336bc2fe1 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/roleimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcespec.go index 4f3fad0c5..c1288f979 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcestatus.go index 847f97c26..b915ba35a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/roleresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/rolespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/rolespec.go index 92fa50276..bc26455d9 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/rolespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/rolespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // RoleSpecApplyConfiguration represents a declarative configuration of the RoleSpec type for use @@ -29,6 +30,7 @@ type RoleSpecApplyConfiguration struct { Resource *RoleResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *RoleSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApp return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *RoleSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *RoleSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/rolestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/rolestatus.go index cc11f42f4..8a2d976a6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/rolestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/rolestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // RoleStatusApplyConfiguration represents a declarative configuration of the RoleStatus type for use // with apply. type RoleStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *RoleResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *RoleResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // RoleStatusApplyConfiguration constructs a declarative configuration of the RoleStatus type for use with @@ -64,3 +66,11 @@ func (b *RoleStatusApplyConfiguration) WithResource(value *RoleResourceStatusApp b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *RoleStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *RoleStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/router.go b/pkg/clients/applyconfiguration/api/v1alpha1/router.go index 3fe5add44..52d6a7d07 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/router.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/router.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerfilter.go index d87275dfc..100978fb6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerimport.go index c48eae55e..d182caade 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerinterface.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerinterface.go index 671f33942..caf20d3d0 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerinterface.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerinterface.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacespec.go index 1af36e749..260239a8f 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,14 +20,16 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // RouterInterfaceSpecApplyConfiguration represents a declarative configuration of the RouterInterfaceSpec type for use // with apply. type RouterInterfaceSpecApplyConfiguration struct { - Type *apiv1alpha1.RouterInterfaceType `json:"type,omitempty"` - RouterRef *apiv1alpha1.KubernetesNameRef `json:"routerRef,omitempty"` - SubnetRef *apiv1alpha1.KubernetesNameRef `json:"subnetRef,omitempty"` + Type *apiv1alpha1.RouterInterfaceType `json:"type,omitempty"` + RouterRef *apiv1alpha1.KubernetesNameRef `json:"routerRef,omitempty"` + SubnetRef *apiv1alpha1.KubernetesNameRef `json:"subnetRef,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` } // RouterInterfaceSpecApplyConfiguration constructs a declarative configuration of the RouterInterfaceSpec type for use with @@ -59,3 +61,11 @@ func (b *RouterInterfaceSpecApplyConfiguration) WithSubnetRef(value apiv1alpha1. b.SubnetRef = &value return b } + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *RouterInterfaceSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *RouterInterfaceSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacestatus.go index 8e162f3bf..fc9c92787 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerinterfacestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,14 +19,16 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // RouterInterfaceStatusApplyConfiguration represents a declarative configuration of the RouterInterfaceStatus type for use // with apply. type RouterInterfaceStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // RouterInterfaceStatusApplyConfiguration constructs a declarative configuration of the RouterInterfaceStatus type for use with @@ -55,3 +57,11 @@ func (b *RouterInterfaceStatusApplyConfiguration) WithID(value string) *RouterIn b.ID = &value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *RouterInterfaceStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *RouterInterfaceStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcespec.go index 2b4cb81b2..4b0a09ff7 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcestatus.go index b89a23529..985da1065 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerspec.go index cf70e4771..c1dde96b9 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // RouterSpecApplyConfiguration represents a declarative configuration of the RouterSpec type for use @@ -29,6 +30,7 @@ type RouterSpecApplyConfiguration struct { Resource *RouterResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *RouterSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsA return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *RouterSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *RouterSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/routerstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/routerstatus.go index ca1eca811..4652956fd 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/routerstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/routerstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // RouterStatusApplyConfiguration represents a declarative configuration of the RouterStatus type for use // with apply. type RouterStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *RouterResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *RouterResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // RouterStatusApplyConfiguration constructs a declarative configuration of the RouterStatus type for use with @@ -64,3 +66,11 @@ func (b *RouterStatusApplyConfiguration) WithResource(value *RouterResourceStatu b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *RouterStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *RouterStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroup.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroup.go index 56ccc6e15..2f05e98c2 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroup.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupfilter.go index e4368095d..f11d7bbdc 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupimport.go index 4faa3f3dd..20855e5a3 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcespec.go index 17d57aafc..f02908f6a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcestatus.go index 2ccdb930a..2709c209b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprule.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprule.go index f6513d5f0..09fa8329e 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprule.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprule.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprulestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprulestatus.go index 8bd924f2a..7d9b31ba6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprulestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygrouprulestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupspec.go index cb624b694..51a5f5a1f 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // SecurityGroupSpecApplyConfiguration represents a declarative configuration of the SecurityGroupSpec type for use @@ -29,6 +30,7 @@ type SecurityGroupSpecApplyConfiguration struct { Resource *SecurityGroupResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *SecurityGroupSpecApplyConfiguration) WithManagedOptions(value *ManagedO return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *SecurityGroupSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *SecurityGroupSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupstatus.go index dae3cc7ac..9237c1699 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/securitygroupstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // SecurityGroupStatusApplyConfiguration represents a declarative configuration of the SecurityGroupStatus type for use // with apply. type SecurityGroupStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *SecurityGroupResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *SecurityGroupResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // SecurityGroupStatusApplyConfiguration constructs a declarative configuration of the SecurityGroupStatus type for use with @@ -64,3 +66,11 @@ func (b *SecurityGroupStatusApplyConfiguration) WithResource(value *SecurityGrou b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *SecurityGroupStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *SecurityGroupStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/server.go b/pkg/clients/applyconfiguration/api/v1alpha1/server.go index 60db77744..21adde247 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/server.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/server.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverbootvolumespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverbootvolumespec.go new file mode 100644 index 000000000..a8456ea36 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverbootvolumespec.go @@ -0,0 +1,52 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// ServerBootVolumeSpecApplyConfiguration represents a declarative configuration of the ServerBootVolumeSpec type for use +// with apply. +type ServerBootVolumeSpecApplyConfiguration struct { + VolumeRef *apiv1alpha1.KubernetesNameRef `json:"volumeRef,omitempty"` + Tag *string `json:"tag,omitempty"` +} + +// ServerBootVolumeSpecApplyConfiguration constructs a declarative configuration of the ServerBootVolumeSpec type for use with +// apply. +func ServerBootVolumeSpec() *ServerBootVolumeSpecApplyConfiguration { + return &ServerBootVolumeSpecApplyConfiguration{} +} + +// WithVolumeRef sets the VolumeRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the VolumeRef field is set to the value of the last call. +func (b *ServerBootVolumeSpecApplyConfiguration) WithVolumeRef(value apiv1alpha1.KubernetesNameRef) *ServerBootVolumeSpecApplyConfiguration { + b.VolumeRef = &value + return b +} + +// WithTag sets the Tag field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Tag field is set to the value of the last call. +func (b *ServerBootVolumeSpecApplyConfiguration) WithTag(value string) *ServerBootVolumeSpecApplyConfiguration { + b.Tag = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverfilter.go index 822ba54d3..1212b6a29 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergroup.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergroup.go index b5bbc8ba0..e534de68c 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergroup.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupfilter.go index 0576765dd..70d12d4fc 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupimport.go index c46e8a88a..0aa17ce03 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcespec.go index 0b9f058e7..08ef8c08a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcestatus.go index 67b1d3be7..ddf1524b2 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprules.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprules.go index e6dc75cef..ab7af2939 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprules.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprules.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprulesstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprulesstatus.go index add47f563..cb61dbfb3 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprulesstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergrouprulesstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupspec.go index 096f6f610..ed08d4bc3 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // ServerGroupSpecApplyConfiguration represents a declarative configuration of the ServerGroupSpec type for use @@ -29,6 +30,7 @@ type ServerGroupSpecApplyConfiguration struct { Resource *ServerGroupResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *ServerGroupSpecApplyConfiguration) WithManagedOptions(value *ManagedOpt return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *ServerGroupSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *ServerGroupSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupstatus.go index b9b392b12..77ba8454b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servergroupstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servergroupstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // ServerGroupStatusApplyConfiguration represents a declarative configuration of the ServerGroupStatus type for use // with apply. type ServerGroupStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *ServerGroupResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *ServerGroupResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // ServerGroupStatusApplyConfiguration constructs a declarative configuration of the ServerGroupStatus type for use with @@ -64,3 +66,11 @@ func (b *ServerGroupStatusApplyConfiguration) WithResource(value *ServerGroupRes b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *ServerGroupStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *ServerGroupStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverimport.go index c93fa9f7d..30ef85c81 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacefixedip.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacefixedip.go index 1bbab2048..ce743b6d0 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacefixedip.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacefixedip.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacestatus.go index 609d5664a..add66fb42 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverinterfacestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servermetadata.go b/pkg/clients/applyconfiguration/api/v1alpha1/servermetadata.go new file mode 100644 index 000000000..7d332a991 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servermetadata.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ServerMetadataApplyConfiguration represents a declarative configuration of the ServerMetadata type for use +// with apply. +type ServerMetadataApplyConfiguration struct { + Key *string `json:"key,omitempty"` + Value *string `json:"value,omitempty"` +} + +// ServerMetadataApplyConfiguration constructs a declarative configuration of the ServerMetadata type for use with +// apply. +func ServerMetadata() *ServerMetadataApplyConfiguration { + return &ServerMetadataApplyConfiguration{} +} + +// WithKey sets the Key field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Key field is set to the value of the last call. +func (b *ServerMetadataApplyConfiguration) WithKey(value string) *ServerMetadataApplyConfiguration { + b.Key = &value + return b +} + +// WithValue sets the Value field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Value field is set to the value of the last call. +func (b *ServerMetadataApplyConfiguration) WithValue(value string) *ServerMetadataApplyConfiguration { + b.Value = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servermetadatastatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/servermetadatastatus.go new file mode 100644 index 000000000..0f978fa89 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servermetadatastatus.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ServerMetadataStatusApplyConfiguration represents a declarative configuration of the ServerMetadataStatus type for use +// with apply. +type ServerMetadataStatusApplyConfiguration struct { + Key *string `json:"key,omitempty"` + Value *string `json:"value,omitempty"` +} + +// ServerMetadataStatusApplyConfiguration constructs a declarative configuration of the ServerMetadataStatus type for use with +// apply. +func ServerMetadataStatus() *ServerMetadataStatusApplyConfiguration { + return &ServerMetadataStatusApplyConfiguration{} +} + +// WithKey sets the Key field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Key field is set to the value of the last call. +func (b *ServerMetadataStatusApplyConfiguration) WithKey(value string) *ServerMetadataStatusApplyConfiguration { + b.Key = &value + return b +} + +// WithValue sets the Value field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Value field is set to the value of the last call. +func (b *ServerMetadataStatusApplyConfiguration) WithValue(value string) *ServerMetadataStatusApplyConfiguration { + b.Value = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverportspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverportspec.go index a09007518..3b812beae 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverportspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverportspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcespec.go index 5233713da..3a95e453d 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,16 +25,19 @@ import ( // ServerResourceSpecApplyConfiguration represents a declarative configuration of the ServerResourceSpec type for use // with apply. type ServerResourceSpecApplyConfiguration struct { - Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` - ImageRef *apiv1alpha1.KubernetesNameRef `json:"imageRef,omitempty"` - FlavorRef *apiv1alpha1.KubernetesNameRef `json:"flavorRef,omitempty"` - UserData *UserDataSpecApplyConfiguration `json:"userData,omitempty"` - Ports []ServerPortSpecApplyConfiguration `json:"ports,omitempty"` - Volumes []ServerVolumeSpecApplyConfiguration `json:"volumes,omitempty"` - ServerGroupRef *apiv1alpha1.KubernetesNameRef `json:"serverGroupRef,omitempty"` - AvailabilityZone *string `json:"availabilityZone,omitempty"` - KeypairRef *apiv1alpha1.KubernetesNameRef `json:"keypairRef,omitempty"` - Tags []apiv1alpha1.ServerTag `json:"tags,omitempty"` + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + ImageRef *apiv1alpha1.KubernetesNameRef `json:"imageRef,omitempty"` + FlavorRef *apiv1alpha1.KubernetesNameRef `json:"flavorRef,omitempty"` + BootVolume *ServerBootVolumeSpecApplyConfiguration `json:"bootVolume,omitempty"` + UserData *UserDataSpecApplyConfiguration `json:"userData,omitempty"` + Ports []ServerPortSpecApplyConfiguration `json:"ports,omitempty"` + Volumes []ServerVolumeSpecApplyConfiguration `json:"volumes,omitempty"` + AvailabilityZone *string `json:"availabilityZone,omitempty"` + KeypairRef *apiv1alpha1.KubernetesNameRef `json:"keypairRef,omitempty"` + Tags []apiv1alpha1.ServerTag `json:"tags,omitempty"` + Metadata []ServerMetadataApplyConfiguration `json:"metadata,omitempty"` + ConfigDrive *bool `json:"configDrive,omitempty"` + SchedulerHints *ServerSchedulerHintsApplyConfiguration `json:"schedulerHints,omitempty"` } // ServerResourceSpecApplyConfiguration constructs a declarative configuration of the ServerResourceSpec type for use with @@ -67,6 +70,14 @@ func (b *ServerResourceSpecApplyConfiguration) WithFlavorRef(value apiv1alpha1.K return b } +// WithBootVolume sets the BootVolume field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the BootVolume field is set to the value of the last call. +func (b *ServerResourceSpecApplyConfiguration) WithBootVolume(value *ServerBootVolumeSpecApplyConfiguration) *ServerResourceSpecApplyConfiguration { + b.BootVolume = value + return b +} + // WithUserData sets the UserData field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the UserData field is set to the value of the last call. @@ -101,14 +112,6 @@ func (b *ServerResourceSpecApplyConfiguration) WithVolumes(values ...*ServerVolu return b } -// WithServerGroupRef sets the ServerGroupRef field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the ServerGroupRef field is set to the value of the last call. -func (b *ServerResourceSpecApplyConfiguration) WithServerGroupRef(value apiv1alpha1.KubernetesNameRef) *ServerResourceSpecApplyConfiguration { - b.ServerGroupRef = &value - return b -} - // WithAvailabilityZone sets the AvailabilityZone field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the AvailabilityZone field is set to the value of the last call. @@ -134,3 +137,32 @@ func (b *ServerResourceSpecApplyConfiguration) WithTags(values ...apiv1alpha1.Se } return b } + +// WithMetadata adds the given value to the Metadata field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Metadata field. +func (b *ServerResourceSpecApplyConfiguration) WithMetadata(values ...*ServerMetadataApplyConfiguration) *ServerResourceSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithMetadata") + } + b.Metadata = append(b.Metadata, *values[i]) + } + return b +} + +// WithConfigDrive sets the ConfigDrive field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ConfigDrive field is set to the value of the last call. +func (b *ServerResourceSpecApplyConfiguration) WithConfigDrive(value bool) *ServerResourceSpecApplyConfiguration { + b.ConfigDrive = &value + return b +} + +// WithSchedulerHints sets the SchedulerHints field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SchedulerHints field is set to the value of the last call. +func (b *ServerResourceSpecApplyConfiguration) WithSchedulerHints(value *ServerSchedulerHintsApplyConfiguration) *ServerResourceSpecApplyConfiguration { + b.SchedulerHints = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcestatus.go index 119583f20..12f1a1032 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,6 +30,8 @@ type ServerResourceStatusApplyConfiguration struct { Volumes []ServerVolumeStatusApplyConfiguration `json:"volumes,omitempty"` Interfaces []ServerInterfaceStatusApplyConfiguration `json:"interfaces,omitempty"` Tags []string `json:"tags,omitempty"` + Metadata []ServerMetadataStatusApplyConfiguration `json:"metadata,omitempty"` + ConfigDrive *bool `json:"configDrive,omitempty"` } // ServerResourceStatusApplyConfiguration constructs a declarative configuration of the ServerResourceStatus type for use with @@ -123,3 +125,24 @@ func (b *ServerResourceStatusApplyConfiguration) WithTags(values ...string) *Ser } return b } + +// WithMetadata adds the given value to the Metadata field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Metadata field. +func (b *ServerResourceStatusApplyConfiguration) WithMetadata(values ...*ServerMetadataStatusApplyConfiguration) *ServerResourceStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithMetadata") + } + b.Metadata = append(b.Metadata, *values[i]) + } + return b +} + +// WithConfigDrive sets the ConfigDrive field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ConfigDrive field is set to the value of the last call. +func (b *ServerResourceStatusApplyConfiguration) WithConfigDrive(value bool) *ServerResourceStatusApplyConfiguration { + b.ConfigDrive = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverschedulerhints.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverschedulerhints.go new file mode 100644 index 000000000..5fc022118 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverschedulerhints.go @@ -0,0 +1,118 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// ServerSchedulerHintsApplyConfiguration represents a declarative configuration of the ServerSchedulerHints type for use +// with apply. +type ServerSchedulerHintsApplyConfiguration struct { + ServerGroupRef *apiv1alpha1.KubernetesNameRef `json:"serverGroupRef,omitempty"` + DifferentHostServerRefs []apiv1alpha1.KubernetesNameRef `json:"differentHostServerRefs,omitempty"` + SameHostServerRefs []apiv1alpha1.KubernetesNameRef `json:"sameHostServerRefs,omitempty"` + Query *string `json:"query,omitempty"` + TargetCell *string `json:"targetCell,omitempty"` + DifferentCell []string `json:"differentCell,omitempty"` + BuildNearHostIP *apiv1alpha1.CIDR `json:"buildNearHostIP,omitempty"` + AdditionalProperties map[string]string `json:"additionalProperties,omitempty"` +} + +// ServerSchedulerHintsApplyConfiguration constructs a declarative configuration of the ServerSchedulerHints type for use with +// apply. +func ServerSchedulerHints() *ServerSchedulerHintsApplyConfiguration { + return &ServerSchedulerHintsApplyConfiguration{} +} + +// WithServerGroupRef sets the ServerGroupRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServerGroupRef field is set to the value of the last call. +func (b *ServerSchedulerHintsApplyConfiguration) WithServerGroupRef(value apiv1alpha1.KubernetesNameRef) *ServerSchedulerHintsApplyConfiguration { + b.ServerGroupRef = &value + return b +} + +// WithDifferentHostServerRefs adds the given value to the DifferentHostServerRefs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the DifferentHostServerRefs field. +func (b *ServerSchedulerHintsApplyConfiguration) WithDifferentHostServerRefs(values ...apiv1alpha1.KubernetesNameRef) *ServerSchedulerHintsApplyConfiguration { + for i := range values { + b.DifferentHostServerRefs = append(b.DifferentHostServerRefs, values[i]) + } + return b +} + +// WithSameHostServerRefs adds the given value to the SameHostServerRefs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the SameHostServerRefs field. +func (b *ServerSchedulerHintsApplyConfiguration) WithSameHostServerRefs(values ...apiv1alpha1.KubernetesNameRef) *ServerSchedulerHintsApplyConfiguration { + for i := range values { + b.SameHostServerRefs = append(b.SameHostServerRefs, values[i]) + } + return b +} + +// WithQuery sets the Query field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Query field is set to the value of the last call. +func (b *ServerSchedulerHintsApplyConfiguration) WithQuery(value string) *ServerSchedulerHintsApplyConfiguration { + b.Query = &value + return b +} + +// WithTargetCell sets the TargetCell field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the TargetCell field is set to the value of the last call. +func (b *ServerSchedulerHintsApplyConfiguration) WithTargetCell(value string) *ServerSchedulerHintsApplyConfiguration { + b.TargetCell = &value + return b +} + +// WithDifferentCell adds the given value to the DifferentCell field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the DifferentCell field. +func (b *ServerSchedulerHintsApplyConfiguration) WithDifferentCell(values ...string) *ServerSchedulerHintsApplyConfiguration { + for i := range values { + b.DifferentCell = append(b.DifferentCell, values[i]) + } + return b +} + +// WithBuildNearHostIP sets the BuildNearHostIP field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the BuildNearHostIP field is set to the value of the last call. +func (b *ServerSchedulerHintsApplyConfiguration) WithBuildNearHostIP(value apiv1alpha1.CIDR) *ServerSchedulerHintsApplyConfiguration { + b.BuildNearHostIP = &value + return b +} + +// WithAdditionalProperties puts the entries into the AdditionalProperties field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the AdditionalProperties field, +// overwriting an existing map entries in AdditionalProperties field with the same key. +func (b *ServerSchedulerHintsApplyConfiguration) WithAdditionalProperties(entries map[string]string) *ServerSchedulerHintsApplyConfiguration { + if b.AdditionalProperties == nil && len(entries) > 0 { + b.AdditionalProperties = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.AdditionalProperties[k] = v + } + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverspec.go index 03baf01b1..95b7b111d 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // ServerSpecApplyConfiguration represents a declarative configuration of the ServerSpec type for use @@ -29,6 +30,7 @@ type ServerSpecApplyConfiguration struct { Resource *ServerResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *ServerSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsA return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *ServerSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *ServerSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serverstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/serverstatus.go index d27cd78a9..43e471a4a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serverstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serverstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // ServerStatusApplyConfiguration represents a declarative configuration of the ServerStatus type for use // with apply. type ServerStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *ServerResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *ServerResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // ServerStatusApplyConfiguration constructs a declarative configuration of the ServerStatus type for use with @@ -64,3 +66,11 @@ func (b *ServerStatusApplyConfiguration) WithResource(value *ServerResourceStatu b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *ServerStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *ServerStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servervolumespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/servervolumespec.go index 9ca2d0c40..bccea241b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servervolumespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servervolumespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servervolumestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/servervolumestatus.go index 15d6b7e4b..601fcf8f9 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servervolumestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servervolumestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/service.go b/pkg/clients/applyconfiguration/api/v1alpha1/service.go index 460eeb720..30619a81b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/service.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/service.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servicefilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/servicefilter.go index 1ca8d84b3..284623ca4 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servicefilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servicefilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serviceimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/serviceimport.go index b719d046d..42ccae04a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serviceimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serviceimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcespec.go index f03f3c54b..5fd35cef6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcestatus.go index 88f1a8fc1..1ee6b1169 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/serviceresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servicespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/servicespec.go index 03cafe9b5..ff6fe4241 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servicespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servicespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // ServiceSpecApplyConfiguration represents a declarative configuration of the ServiceSpec type for use @@ -29,6 +30,7 @@ type ServiceSpecApplyConfiguration struct { Resource *ServiceResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *ServiceSpecApplyConfiguration) WithManagedOptions(value *ManagedOptions return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *ServiceSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *ServiceSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/servicestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/servicestatus.go index 80bf199ba..b7bc37269 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/servicestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/servicestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // ServiceStatusApplyConfiguration represents a declarative configuration of the ServiceStatus type for use // with apply. type ServiceStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *ServiceResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *ServiceResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // ServiceStatusApplyConfiguration constructs a declarative configuration of the ServiceStatus type for use with @@ -64,3 +66,11 @@ func (b *ServiceStatusApplyConfiguration) WithResource(value *ServiceResourceSta b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *ServiceStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *ServiceStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/sharenetwork.go b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetwork.go new file mode 100644 index 000000000..8fcacbb0b --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetwork.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ShareNetworkApplyConfiguration represents a declarative configuration of the ShareNetwork type for use +// with apply. +type ShareNetworkApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *ShareNetworkSpecApplyConfiguration `json:"spec,omitempty"` + Status *ShareNetworkStatusApplyConfiguration `json:"status,omitempty"` +} + +// ShareNetwork constructs a declarative configuration of the ShareNetwork type for use with +// apply. +func ShareNetwork(name, namespace string) *ShareNetworkApplyConfiguration { + b := &ShareNetworkApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("ShareNetwork") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractShareNetwork extracts the applied configuration owned by fieldManager from +// shareNetwork. If no managedFields are found in shareNetwork for fieldManager, a +// ShareNetworkApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// shareNetwork must be a unmodified ShareNetwork API object that was retrieved from the Kubernetes API. +// ExtractShareNetwork provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractShareNetwork(shareNetwork *apiv1alpha1.ShareNetwork, fieldManager string) (*ShareNetworkApplyConfiguration, error) { + return extractShareNetwork(shareNetwork, fieldManager, "") +} + +// ExtractShareNetworkStatus is the same as ExtractShareNetwork except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractShareNetworkStatus(shareNetwork *apiv1alpha1.ShareNetwork, fieldManager string) (*ShareNetworkApplyConfiguration, error) { + return extractShareNetwork(shareNetwork, fieldManager, "status") +} + +func extractShareNetwork(shareNetwork *apiv1alpha1.ShareNetwork, fieldManager string, subresource string) (*ShareNetworkApplyConfiguration, error) { + b := &ShareNetworkApplyConfiguration{} + err := managedfields.ExtractInto(shareNetwork, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetwork"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(shareNetwork.Name) + b.WithNamespace(shareNetwork.Namespace) + + b.WithKind("ShareNetwork") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b ShareNetworkApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithKind(value string) *ShareNetworkApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithAPIVersion(value string) *ShareNetworkApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithName(value string) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithGenerateName(value string) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithNamespace(value string) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithUID(value types.UID) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithResourceVersion(value string) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithGeneration(value int64) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ShareNetworkApplyConfiguration) WithLabels(entries map[string]string) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ShareNetworkApplyConfiguration) WithAnnotations(entries map[string]string) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *ShareNetworkApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *ShareNetworkApplyConfiguration) WithFinalizers(values ...string) *ShareNetworkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *ShareNetworkApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithSpec(value *ShareNetworkSpecApplyConfiguration) *ShareNetworkApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ShareNetworkApplyConfiguration) WithStatus(value *ShareNetworkStatusApplyConfiguration) *ShareNetworkApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *ShareNetworkApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *ShareNetworkApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ShareNetworkApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *ShareNetworkApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkfilter.go new file mode 100644 index 000000000..e15de0ff6 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkfilter.go @@ -0,0 +1,52 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// ShareNetworkFilterApplyConfiguration represents a declarative configuration of the ShareNetworkFilter type for use +// with apply. +type ShareNetworkFilterApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` +} + +// ShareNetworkFilterApplyConfiguration constructs a declarative configuration of the ShareNetworkFilter type for use with +// apply. +func ShareNetworkFilter() *ShareNetworkFilterApplyConfiguration { + return &ShareNetworkFilterApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ShareNetworkFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *ShareNetworkFilterApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *ShareNetworkFilterApplyConfiguration) WithDescription(value string) *ShareNetworkFilterApplyConfiguration { + b.Description = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkimport.go new file mode 100644 index 000000000..5343a304a --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkimport.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ShareNetworkImportApplyConfiguration represents a declarative configuration of the ShareNetworkImport type for use +// with apply. +type ShareNetworkImportApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Filter *ShareNetworkFilterApplyConfiguration `json:"filter,omitempty"` +} + +// ShareNetworkImportApplyConfiguration constructs a declarative configuration of the ShareNetworkImport type for use with +// apply. +func ShareNetworkImport() *ShareNetworkImportApplyConfiguration { + return &ShareNetworkImportApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *ShareNetworkImportApplyConfiguration) WithID(value string) *ShareNetworkImportApplyConfiguration { + b.ID = &value + return b +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *ShareNetworkImportApplyConfiguration) WithFilter(value *ShareNetworkFilterApplyConfiguration) *ShareNetworkImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkresourcespec.go new file mode 100644 index 000000000..1bdaf30f7 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkresourcespec.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// ShareNetworkResourceSpecApplyConfiguration represents a declarative configuration of the ShareNetworkResourceSpec type for use +// with apply. +type ShareNetworkResourceSpecApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + NetworkRef *apiv1alpha1.KubernetesNameRef `json:"networkRef,omitempty"` + SubnetRef *apiv1alpha1.KubernetesNameRef `json:"subnetRef,omitempty"` +} + +// ShareNetworkResourceSpecApplyConfiguration constructs a declarative configuration of the ShareNetworkResourceSpec type for use with +// apply. +func ShareNetworkResourceSpec() *ShareNetworkResourceSpecApplyConfiguration { + return &ShareNetworkResourceSpecApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ShareNetworkResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *ShareNetworkResourceSpecApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *ShareNetworkResourceSpecApplyConfiguration) WithDescription(value string) *ShareNetworkResourceSpecApplyConfiguration { + b.Description = &value + return b +} + +// WithNetworkRef sets the NetworkRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the NetworkRef field is set to the value of the last call. +func (b *ShareNetworkResourceSpecApplyConfiguration) WithNetworkRef(value apiv1alpha1.KubernetesNameRef) *ShareNetworkResourceSpecApplyConfiguration { + b.NetworkRef = &value + return b +} + +// WithSubnetRef sets the SubnetRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SubnetRef field is set to the value of the last call. +func (b *ShareNetworkResourceSpecApplyConfiguration) WithSubnetRef(value apiv1alpha1.KubernetesNameRef) *ShareNetworkResourceSpecApplyConfiguration { + b.SubnetRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkresourcestatus.go new file mode 100644 index 000000000..9ffc47942 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkresourcestatus.go @@ -0,0 +1,133 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ShareNetworkResourceStatusApplyConfiguration represents a declarative configuration of the ShareNetworkResourceStatus type for use +// with apply. +type ShareNetworkResourceStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + NeutronNetID *string `json:"neutronNetID,omitempty"` + NeutronSubnetID *string `json:"neutronSubnetID,omitempty"` + NetworkType *string `json:"networkType,omitempty"` + SegmentationID *int32 `json:"segmentationID,omitempty"` + CIDR *string `json:"cidr,omitempty"` + IPVersion *int32 `json:"ipVersion,omitempty"` + ProjectID *string `json:"projectID,omitempty"` + CreatedAt *v1.Time `json:"createdAt,omitempty"` + UpdatedAt *v1.Time `json:"updatedAt,omitempty"` +} + +// ShareNetworkResourceStatusApplyConfiguration constructs a declarative configuration of the ShareNetworkResourceStatus type for use with +// apply. +func ShareNetworkResourceStatus() *ShareNetworkResourceStatusApplyConfiguration { + return &ShareNetworkResourceStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithName(value string) *ShareNetworkResourceStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithDescription(value string) *ShareNetworkResourceStatusApplyConfiguration { + b.Description = &value + return b +} + +// WithNeutronNetID sets the NeutronNetID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the NeutronNetID field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithNeutronNetID(value string) *ShareNetworkResourceStatusApplyConfiguration { + b.NeutronNetID = &value + return b +} + +// WithNeutronSubnetID sets the NeutronSubnetID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the NeutronSubnetID field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithNeutronSubnetID(value string) *ShareNetworkResourceStatusApplyConfiguration { + b.NeutronSubnetID = &value + return b +} + +// WithNetworkType sets the NetworkType field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the NetworkType field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithNetworkType(value string) *ShareNetworkResourceStatusApplyConfiguration { + b.NetworkType = &value + return b +} + +// WithSegmentationID sets the SegmentationID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SegmentationID field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithSegmentationID(value int32) *ShareNetworkResourceStatusApplyConfiguration { + b.SegmentationID = &value + return b +} + +// WithCIDR sets the CIDR field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CIDR field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithCIDR(value string) *ShareNetworkResourceStatusApplyConfiguration { + b.CIDR = &value + return b +} + +// WithIPVersion sets the IPVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the IPVersion field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithIPVersion(value int32) *ShareNetworkResourceStatusApplyConfiguration { + b.IPVersion = &value + return b +} + +// WithProjectID sets the ProjectID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectID field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithProjectID(value string) *ShareNetworkResourceStatusApplyConfiguration { + b.ProjectID = &value + return b +} + +// WithCreatedAt sets the CreatedAt field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreatedAt field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithCreatedAt(value v1.Time) *ShareNetworkResourceStatusApplyConfiguration { + b.CreatedAt = &value + return b +} + +// WithUpdatedAt sets the UpdatedAt field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UpdatedAt field is set to the value of the last call. +func (b *ShareNetworkResourceStatusApplyConfiguration) WithUpdatedAt(value v1.Time) *ShareNetworkResourceStatusApplyConfiguration { + b.UpdatedAt = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkspec.go new file mode 100644 index 000000000..ac675c764 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkspec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ShareNetworkSpecApplyConfiguration represents a declarative configuration of the ShareNetworkSpec type for use +// with apply. +type ShareNetworkSpecApplyConfiguration struct { + Import *ShareNetworkImportApplyConfiguration `json:"import,omitempty"` + Resource *ShareNetworkResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// ShareNetworkSpecApplyConfiguration constructs a declarative configuration of the ShareNetworkSpec type for use with +// apply. +func ShareNetworkSpec() *ShareNetworkSpecApplyConfiguration { + return &ShareNetworkSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *ShareNetworkSpecApplyConfiguration) WithImport(value *ShareNetworkImportApplyConfiguration) *ShareNetworkSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *ShareNetworkSpecApplyConfiguration) WithResource(value *ShareNetworkResourceSpecApplyConfiguration) *ShareNetworkSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *ShareNetworkSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *ShareNetworkSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *ShareNetworkSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *ShareNetworkSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *ShareNetworkSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *ShareNetworkSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *ShareNetworkSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *ShareNetworkSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkstatus.go new file mode 100644 index 000000000..e586e90ee --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/sharenetworkstatus.go @@ -0,0 +1,76 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ShareNetworkStatusApplyConfiguration represents a declarative configuration of the ShareNetworkStatus type for use +// with apply. +type ShareNetworkStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *ShareNetworkResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// ShareNetworkStatusApplyConfiguration constructs a declarative configuration of the ShareNetworkStatus type for use with +// apply. +func ShareNetworkStatus() *ShareNetworkStatusApplyConfiguration { + return &ShareNetworkStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *ShareNetworkStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *ShareNetworkStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *ShareNetworkStatusApplyConfiguration) WithID(value string) *ShareNetworkStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *ShareNetworkStatusApplyConfiguration) WithResource(value *ShareNetworkResourceStatusApplyConfiguration) *ShareNetworkStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *ShareNetworkStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *ShareNetworkStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnet.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnet.go index 0c0f127fc..b4d653764 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnet.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnet.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetfilter.go index 7eac6055a..77070b0b1 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnetfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetfilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetgateway.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetgateway.go index e82635429..8982b39d4 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnetgateway.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetgateway.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetimport.go index 7b8255fef..483fe0f1e 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnetimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcespec.go index 1e0e65238..73f73099c 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcestatus.go index 8c0f8f918..7da523a8d 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetspec.go index ff3c3c27c..c32747ef5 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnetspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // SubnetSpecApplyConfiguration represents a declarative configuration of the SubnetSpec type for use @@ -29,6 +30,7 @@ type SubnetSpecApplyConfiguration struct { Resource *SubnetResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *SubnetSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsA return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *SubnetSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *SubnetSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetstatus.go index 8b8b1d216..fde0cef71 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/subnetstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // SubnetStatusApplyConfiguration represents a declarative configuration of the SubnetStatus type for use // with apply. type SubnetStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *SubnetResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *SubnetResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // SubnetStatusApplyConfiguration constructs a declarative configuration of the SubnetStatus type for use with @@ -64,3 +66,11 @@ func (b *SubnetStatusApplyConfiguration) WithResource(value *SubnetResourceStatu b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *SubnetStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *SubnetStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunk.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunk.go new file mode 100644 index 000000000..60ee92b13 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunk.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TrunkApplyConfiguration represents a declarative configuration of the Trunk type for use +// with apply. +type TrunkApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *TrunkSpecApplyConfiguration `json:"spec,omitempty"` + Status *TrunkStatusApplyConfiguration `json:"status,omitempty"` +} + +// Trunk constructs a declarative configuration of the Trunk type for use with +// apply. +func Trunk(name, namespace string) *TrunkApplyConfiguration { + b := &TrunkApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("Trunk") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractTrunk extracts the applied configuration owned by fieldManager from +// trunk. If no managedFields are found in trunk for fieldManager, a +// TrunkApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// trunk must be a unmodified Trunk API object that was retrieved from the Kubernetes API. +// ExtractTrunk provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractTrunk(trunk *apiv1alpha1.Trunk, fieldManager string) (*TrunkApplyConfiguration, error) { + return extractTrunk(trunk, fieldManager, "") +} + +// ExtractTrunkStatus is the same as ExtractTrunk except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractTrunkStatus(trunk *apiv1alpha1.Trunk, fieldManager string) (*TrunkApplyConfiguration, error) { + return extractTrunk(trunk, fieldManager, "status") +} + +func extractTrunk(trunk *apiv1alpha1.Trunk, fieldManager string, subresource string) (*TrunkApplyConfiguration, error) { + b := &TrunkApplyConfiguration{} + err := managedfields.ExtractInto(trunk, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Trunk"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(trunk.Name) + b.WithNamespace(trunk.Namespace) + + b.WithKind("Trunk") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b TrunkApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithKind(value string) *TrunkApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithAPIVersion(value string) *TrunkApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithName(value string) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithGenerateName(value string) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithNamespace(value string) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithUID(value types.UID) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithResourceVersion(value string) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithGeneration(value int64) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithCreationTimestamp(value metav1.Time) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TrunkApplyConfiguration) WithLabels(entries map[string]string) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TrunkApplyConfiguration) WithAnnotations(entries map[string]string) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TrunkApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TrunkApplyConfiguration) WithFinalizers(values ...string) *TrunkApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TrunkApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithSpec(value *TrunkSpecApplyConfiguration) *TrunkApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TrunkApplyConfiguration) WithStatus(value *TrunkStatusApplyConfiguration) *TrunkApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *TrunkApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *TrunkApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TrunkApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *TrunkApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunkfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunkfilter.go new file mode 100644 index 000000000..e6efbaa32 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunkfilter.go @@ -0,0 +1,120 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// TrunkFilterApplyConfiguration represents a declarative configuration of the TrunkFilter type for use +// with apply. +type TrunkFilterApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *apiv1alpha1.NeutronDescription `json:"description,omitempty"` + PortRef *apiv1alpha1.KubernetesNameRef `json:"portRef,omitempty"` + ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + AdminStateUp *bool `json:"adminStateUp,omitempty"` + FilterByNeutronTagsApplyConfiguration `json:",inline"` +} + +// TrunkFilterApplyConfiguration constructs a declarative configuration of the TrunkFilter type for use with +// apply. +func TrunkFilter() *TrunkFilterApplyConfiguration { + return &TrunkFilterApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TrunkFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *TrunkFilterApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *TrunkFilterApplyConfiguration) WithDescription(value apiv1alpha1.NeutronDescription) *TrunkFilterApplyConfiguration { + b.Description = &value + return b +} + +// WithPortRef sets the PortRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PortRef field is set to the value of the last call. +func (b *TrunkFilterApplyConfiguration) WithPortRef(value apiv1alpha1.KubernetesNameRef) *TrunkFilterApplyConfiguration { + b.PortRef = &value + return b +} + +// WithProjectRef sets the ProjectRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectRef field is set to the value of the last call. +func (b *TrunkFilterApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *TrunkFilterApplyConfiguration { + b.ProjectRef = &value + return b +} + +// WithAdminStateUp sets the AdminStateUp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the AdminStateUp field is set to the value of the last call. +func (b *TrunkFilterApplyConfiguration) WithAdminStateUp(value bool) *TrunkFilterApplyConfiguration { + b.AdminStateUp = &value + return b +} + +// WithTags adds the given value to the Tags field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Tags field. +func (b *TrunkFilterApplyConfiguration) WithTags(values ...apiv1alpha1.NeutronTag) *TrunkFilterApplyConfiguration { + for i := range values { + b.FilterByNeutronTagsApplyConfiguration.Tags = append(b.FilterByNeutronTagsApplyConfiguration.Tags, values[i]) + } + return b +} + +// WithTagsAny adds the given value to the TagsAny field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the TagsAny field. +func (b *TrunkFilterApplyConfiguration) WithTagsAny(values ...apiv1alpha1.NeutronTag) *TrunkFilterApplyConfiguration { + for i := range values { + b.FilterByNeutronTagsApplyConfiguration.TagsAny = append(b.FilterByNeutronTagsApplyConfiguration.TagsAny, values[i]) + } + return b +} + +// WithNotTags adds the given value to the NotTags field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the NotTags field. +func (b *TrunkFilterApplyConfiguration) WithNotTags(values ...apiv1alpha1.NeutronTag) *TrunkFilterApplyConfiguration { + for i := range values { + b.FilterByNeutronTagsApplyConfiguration.NotTags = append(b.FilterByNeutronTagsApplyConfiguration.NotTags, values[i]) + } + return b +} + +// WithNotTagsAny adds the given value to the NotTagsAny field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the NotTagsAny field. +func (b *TrunkFilterApplyConfiguration) WithNotTagsAny(values ...apiv1alpha1.NeutronTag) *TrunkFilterApplyConfiguration { + for i := range values { + b.FilterByNeutronTagsApplyConfiguration.NotTagsAny = append(b.FilterByNeutronTagsApplyConfiguration.NotTagsAny, values[i]) + } + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunkimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunkimport.go new file mode 100644 index 000000000..960ff678d --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunkimport.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// TrunkImportApplyConfiguration represents a declarative configuration of the TrunkImport type for use +// with apply. +type TrunkImportApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Filter *TrunkFilterApplyConfiguration `json:"filter,omitempty"` +} + +// TrunkImportApplyConfiguration constructs a declarative configuration of the TrunkImport type for use with +// apply. +func TrunkImport() *TrunkImportApplyConfiguration { + return &TrunkImportApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *TrunkImportApplyConfiguration) WithID(value string) *TrunkImportApplyConfiguration { + b.ID = &value + return b +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *TrunkImportApplyConfiguration) WithFilter(value *TrunkFilterApplyConfiguration) *TrunkImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunkresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunkresourcespec.go new file mode 100644 index 000000000..5dbdf2846 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunkresourcespec.go @@ -0,0 +1,104 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// TrunkResourceSpecApplyConfiguration represents a declarative configuration of the TrunkResourceSpec type for use +// with apply. +type TrunkResourceSpecApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *apiv1alpha1.NeutronDescription `json:"description,omitempty"` + PortRef *apiv1alpha1.KubernetesNameRef `json:"portRef,omitempty"` + ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"` + AdminStateUp *bool `json:"adminStateUp,omitempty"` + Subports []TrunkSubportSpecApplyConfiguration `json:"subports,omitempty"` + Tags []apiv1alpha1.NeutronTag `json:"tags,omitempty"` +} + +// TrunkResourceSpecApplyConfiguration constructs a declarative configuration of the TrunkResourceSpec type for use with +// apply. +func TrunkResourceSpec() *TrunkResourceSpecApplyConfiguration { + return &TrunkResourceSpecApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TrunkResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *TrunkResourceSpecApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *TrunkResourceSpecApplyConfiguration) WithDescription(value apiv1alpha1.NeutronDescription) *TrunkResourceSpecApplyConfiguration { + b.Description = &value + return b +} + +// WithPortRef sets the PortRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PortRef field is set to the value of the last call. +func (b *TrunkResourceSpecApplyConfiguration) WithPortRef(value apiv1alpha1.KubernetesNameRef) *TrunkResourceSpecApplyConfiguration { + b.PortRef = &value + return b +} + +// WithProjectRef sets the ProjectRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectRef field is set to the value of the last call. +func (b *TrunkResourceSpecApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *TrunkResourceSpecApplyConfiguration { + b.ProjectRef = &value + return b +} + +// WithAdminStateUp sets the AdminStateUp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the AdminStateUp field is set to the value of the last call. +func (b *TrunkResourceSpecApplyConfiguration) WithAdminStateUp(value bool) *TrunkResourceSpecApplyConfiguration { + b.AdminStateUp = &value + return b +} + +// WithSubports adds the given value to the Subports field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Subports field. +func (b *TrunkResourceSpecApplyConfiguration) WithSubports(values ...*TrunkSubportSpecApplyConfiguration) *TrunkResourceSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithSubports") + } + b.Subports = append(b.Subports, *values[i]) + } + return b +} + +// WithTags adds the given value to the Tags field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Tags field. +func (b *TrunkResourceSpecApplyConfiguration) WithTags(values ...apiv1alpha1.NeutronTag) *TrunkResourceSpecApplyConfiguration { + for i := range values { + b.Tags = append(b.Tags, values[i]) + } + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunkresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunkresourcestatus.go new file mode 100644 index 000000000..1904b9fa4 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunkresourcestatus.go @@ -0,0 +1,147 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TrunkResourceStatusApplyConfiguration represents a declarative configuration of the TrunkResourceStatus type for use +// with apply. +type TrunkResourceStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + PortID *string `json:"portID,omitempty"` + ProjectID *string `json:"projectID,omitempty"` + TenantID *string `json:"tenantID,omitempty"` + Status *string `json:"status,omitempty"` + Tags []string `json:"tags,omitempty"` + NeutronStatusMetadataApplyConfiguration `json:",inline"` + AdminStateUp *bool `json:"adminStateUp,omitempty"` + Subports []TrunkSubportStatusApplyConfiguration `json:"subports,omitempty"` +} + +// TrunkResourceStatusApplyConfiguration constructs a declarative configuration of the TrunkResourceStatus type for use with +// apply. +func TrunkResourceStatus() *TrunkResourceStatusApplyConfiguration { + return &TrunkResourceStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithName(value string) *TrunkResourceStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithDescription(value string) *TrunkResourceStatusApplyConfiguration { + b.Description = &value + return b +} + +// WithPortID sets the PortID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PortID field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithPortID(value string) *TrunkResourceStatusApplyConfiguration { + b.PortID = &value + return b +} + +// WithProjectID sets the ProjectID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ProjectID field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithProjectID(value string) *TrunkResourceStatusApplyConfiguration { + b.ProjectID = &value + return b +} + +// WithTenantID sets the TenantID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the TenantID field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithTenantID(value string) *TrunkResourceStatusApplyConfiguration { + b.TenantID = &value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithStatus(value string) *TrunkResourceStatusApplyConfiguration { + b.Status = &value + return b +} + +// WithTags adds the given value to the Tags field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Tags field. +func (b *TrunkResourceStatusApplyConfiguration) WithTags(values ...string) *TrunkResourceStatusApplyConfiguration { + for i := range values { + b.Tags = append(b.Tags, values[i]) + } + return b +} + +// WithCreatedAt sets the CreatedAt field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreatedAt field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithCreatedAt(value v1.Time) *TrunkResourceStatusApplyConfiguration { + b.NeutronStatusMetadataApplyConfiguration.CreatedAt = &value + return b +} + +// WithUpdatedAt sets the UpdatedAt field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UpdatedAt field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithUpdatedAt(value v1.Time) *TrunkResourceStatusApplyConfiguration { + b.NeutronStatusMetadataApplyConfiguration.UpdatedAt = &value + return b +} + +// WithRevisionNumber sets the RevisionNumber field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the RevisionNumber field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithRevisionNumber(value int64) *TrunkResourceStatusApplyConfiguration { + b.NeutronStatusMetadataApplyConfiguration.RevisionNumber = &value + return b +} + +// WithAdminStateUp sets the AdminStateUp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the AdminStateUp field is set to the value of the last call. +func (b *TrunkResourceStatusApplyConfiguration) WithAdminStateUp(value bool) *TrunkResourceStatusApplyConfiguration { + b.AdminStateUp = &value + return b +} + +// WithSubports adds the given value to the Subports field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Subports field. +func (b *TrunkResourceStatusApplyConfiguration) WithSubports(values ...*TrunkSubportStatusApplyConfiguration) *TrunkResourceStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithSubports") + } + b.Subports = append(b.Subports, *values[i]) + } + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunkspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunkspec.go new file mode 100644 index 000000000..12f298757 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunkspec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TrunkSpecApplyConfiguration represents a declarative configuration of the TrunkSpec type for use +// with apply. +type TrunkSpecApplyConfiguration struct { + Import *TrunkImportApplyConfiguration `json:"import,omitempty"` + Resource *TrunkResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// TrunkSpecApplyConfiguration constructs a declarative configuration of the TrunkSpec type for use with +// apply. +func TrunkSpec() *TrunkSpecApplyConfiguration { + return &TrunkSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *TrunkSpecApplyConfiguration) WithImport(value *TrunkImportApplyConfiguration) *TrunkSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *TrunkSpecApplyConfiguration) WithResource(value *TrunkResourceSpecApplyConfiguration) *TrunkSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *TrunkSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *TrunkSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *TrunkSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *TrunkSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *TrunkSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *TrunkSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *TrunkSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *TrunkSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunkstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunkstatus.go new file mode 100644 index 000000000..5e7b3d922 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunkstatus.go @@ -0,0 +1,76 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TrunkStatusApplyConfiguration represents a declarative configuration of the TrunkStatus type for use +// with apply. +type TrunkStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *TrunkResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// TrunkStatusApplyConfiguration constructs a declarative configuration of the TrunkStatus type for use with +// apply. +func TrunkStatus() *TrunkStatusApplyConfiguration { + return &TrunkStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *TrunkStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *TrunkStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *TrunkStatusApplyConfiguration) WithID(value string) *TrunkStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *TrunkStatusApplyConfiguration) WithResource(value *TrunkResourceStatusApplyConfiguration) *TrunkStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *TrunkStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *TrunkStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunksubportspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunksubportspec.go new file mode 100644 index 000000000..16625b28b --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunksubportspec.go @@ -0,0 +1,61 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// TrunkSubportSpecApplyConfiguration represents a declarative configuration of the TrunkSubportSpec type for use +// with apply. +type TrunkSubportSpecApplyConfiguration struct { + PortRef *apiv1alpha1.KubernetesNameRef `json:"portRef,omitempty"` + SegmentationID *int32 `json:"segmentationID,omitempty"` + SegmentationType *string `json:"segmentationType,omitempty"` +} + +// TrunkSubportSpecApplyConfiguration constructs a declarative configuration of the TrunkSubportSpec type for use with +// apply. +func TrunkSubportSpec() *TrunkSubportSpecApplyConfiguration { + return &TrunkSubportSpecApplyConfiguration{} +} + +// WithPortRef sets the PortRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PortRef field is set to the value of the last call. +func (b *TrunkSubportSpecApplyConfiguration) WithPortRef(value apiv1alpha1.KubernetesNameRef) *TrunkSubportSpecApplyConfiguration { + b.PortRef = &value + return b +} + +// WithSegmentationID sets the SegmentationID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SegmentationID field is set to the value of the last call. +func (b *TrunkSubportSpecApplyConfiguration) WithSegmentationID(value int32) *TrunkSubportSpecApplyConfiguration { + b.SegmentationID = &value + return b +} + +// WithSegmentationType sets the SegmentationType field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SegmentationType field is set to the value of the last call. +func (b *TrunkSubportSpecApplyConfiguration) WithSegmentationType(value string) *TrunkSubportSpecApplyConfiguration { + b.SegmentationType = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/trunksubportstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/trunksubportstatus.go new file mode 100644 index 000000000..b782fa334 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/trunksubportstatus.go @@ -0,0 +1,57 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// TrunkSubportStatusApplyConfiguration represents a declarative configuration of the TrunkSubportStatus type for use +// with apply. +type TrunkSubportStatusApplyConfiguration struct { + PortID *string `json:"portID,omitempty"` + SegmentationID *int32 `json:"segmentationID,omitempty"` + SegmentationType *string `json:"segmentationType,omitempty"` +} + +// TrunkSubportStatusApplyConfiguration constructs a declarative configuration of the TrunkSubportStatus type for use with +// apply. +func TrunkSubportStatus() *TrunkSubportStatusApplyConfiguration { + return &TrunkSubportStatusApplyConfiguration{} +} + +// WithPortID sets the PortID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PortID field is set to the value of the last call. +func (b *TrunkSubportStatusApplyConfiguration) WithPortID(value string) *TrunkSubportStatusApplyConfiguration { + b.PortID = &value + return b +} + +// WithSegmentationID sets the SegmentationID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SegmentationID field is set to the value of the last call. +func (b *TrunkSubportStatusApplyConfiguration) WithSegmentationID(value int32) *TrunkSubportStatusApplyConfiguration { + b.SegmentationID = &value + return b +} + +// WithSegmentationType sets the SegmentationType field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SegmentationType field is set to the value of the last call. +func (b *TrunkSubportStatusApplyConfiguration) WithSegmentationType(value string) *TrunkSubportStatusApplyConfiguration { + b.SegmentationType = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/user.go b/pkg/clients/applyconfiguration/api/v1alpha1/user.go new file mode 100644 index 000000000..8c7077cc4 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/user.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// UserApplyConfiguration represents a declarative configuration of the User type for use +// with apply. +type UserApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *UserSpecApplyConfiguration `json:"spec,omitempty"` + Status *UserStatusApplyConfiguration `json:"status,omitempty"` +} + +// User constructs a declarative configuration of the User type for use with +// apply. +func User(name, namespace string) *UserApplyConfiguration { + b := &UserApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("User") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractUser extracts the applied configuration owned by fieldManager from +// user. If no managedFields are found in user for fieldManager, a +// UserApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// user must be a unmodified User API object that was retrieved from the Kubernetes API. +// ExtractUser provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractUser(user *apiv1alpha1.User, fieldManager string) (*UserApplyConfiguration, error) { + return extractUser(user, fieldManager, "") +} + +// ExtractUserStatus is the same as ExtractUser except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractUserStatus(user *apiv1alpha1.User, fieldManager string) (*UserApplyConfiguration, error) { + return extractUser(user, fieldManager, "status") +} + +func extractUser(user *apiv1alpha1.User, fieldManager string, subresource string) (*UserApplyConfiguration, error) { + b := &UserApplyConfiguration{} + err := managedfields.ExtractInto(user, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.User"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(user.Name) + b.WithNamespace(user.Namespace) + + b.WithKind("User") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b UserApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *UserApplyConfiguration) WithKind(value string) *UserApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *UserApplyConfiguration) WithAPIVersion(value string) *UserApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *UserApplyConfiguration) WithName(value string) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *UserApplyConfiguration) WithGenerateName(value string) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *UserApplyConfiguration) WithNamespace(value string) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *UserApplyConfiguration) WithUID(value types.UID) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *UserApplyConfiguration) WithResourceVersion(value string) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *UserApplyConfiguration) WithGeneration(value int64) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *UserApplyConfiguration) WithCreationTimestamp(value metav1.Time) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *UserApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *UserApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *UserApplyConfiguration) WithLabels(entries map[string]string) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *UserApplyConfiguration) WithAnnotations(entries map[string]string) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *UserApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *UserApplyConfiguration) WithFinalizers(values ...string) *UserApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *UserApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *UserApplyConfiguration) WithSpec(value *UserSpecApplyConfiguration) *UserApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *UserApplyConfiguration) WithStatus(value *UserStatusApplyConfiguration) *UserApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *UserApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *UserApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *UserApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *UserApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/userdataspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/userdataspec.go index bbfc17368..394503c52 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/userdataspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/userdataspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/userfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/userfilter.go new file mode 100644 index 000000000..3cc89f7ec --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/userfilter.go @@ -0,0 +1,52 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// UserFilterApplyConfiguration represents a declarative configuration of the UserFilter type for use +// with apply. +type UserFilterApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + DomainRef *apiv1alpha1.KubernetesNameRef `json:"domainRef,omitempty"` +} + +// UserFilterApplyConfiguration constructs a declarative configuration of the UserFilter type for use with +// apply. +func UserFilter() *UserFilterApplyConfiguration { + return &UserFilterApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *UserFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *UserFilterApplyConfiguration { + b.Name = &value + return b +} + +// WithDomainRef sets the DomainRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainRef field is set to the value of the last call. +func (b *UserFilterApplyConfiguration) WithDomainRef(value apiv1alpha1.KubernetesNameRef) *UserFilterApplyConfiguration { + b.DomainRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/userimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/userimport.go new file mode 100644 index 000000000..4497cbde2 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/userimport.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// UserImportApplyConfiguration represents a declarative configuration of the UserImport type for use +// with apply. +type UserImportApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Filter *UserFilterApplyConfiguration `json:"filter,omitempty"` +} + +// UserImportApplyConfiguration constructs a declarative configuration of the UserImport type for use with +// apply. +func UserImport() *UserImportApplyConfiguration { + return &UserImportApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *UserImportApplyConfiguration) WithID(value string) *UserImportApplyConfiguration { + b.ID = &value + return b +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *UserImportApplyConfiguration) WithFilter(value *UserFilterApplyConfiguration) *UserImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/userresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/userresourcespec.go new file mode 100644 index 000000000..bd0bab7c6 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/userresourcespec.go @@ -0,0 +1,88 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// UserResourceSpecApplyConfiguration represents a declarative configuration of the UserResourceSpec type for use +// with apply. +type UserResourceSpecApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + DomainRef *apiv1alpha1.KubernetesNameRef `json:"domainRef,omitempty"` + DefaultProjectRef *apiv1alpha1.KubernetesNameRef `json:"defaultProjectRef,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + PasswordRef *apiv1alpha1.KubernetesNameRef `json:"passwordRef,omitempty"` +} + +// UserResourceSpecApplyConfiguration constructs a declarative configuration of the UserResourceSpec type for use with +// apply. +func UserResourceSpec() *UserResourceSpecApplyConfiguration { + return &UserResourceSpecApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *UserResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *UserResourceSpecApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *UserResourceSpecApplyConfiguration) WithDescription(value string) *UserResourceSpecApplyConfiguration { + b.Description = &value + return b +} + +// WithDomainRef sets the DomainRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainRef field is set to the value of the last call. +func (b *UserResourceSpecApplyConfiguration) WithDomainRef(value apiv1alpha1.KubernetesNameRef) *UserResourceSpecApplyConfiguration { + b.DomainRef = &value + return b +} + +// WithDefaultProjectRef sets the DefaultProjectRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DefaultProjectRef field is set to the value of the last call. +func (b *UserResourceSpecApplyConfiguration) WithDefaultProjectRef(value apiv1alpha1.KubernetesNameRef) *UserResourceSpecApplyConfiguration { + b.DefaultProjectRef = &value + return b +} + +// WithEnabled sets the Enabled field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Enabled field is set to the value of the last call. +func (b *UserResourceSpecApplyConfiguration) WithEnabled(value bool) *UserResourceSpecApplyConfiguration { + b.Enabled = &value + return b +} + +// WithPasswordRef sets the PasswordRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PasswordRef field is set to the value of the last call. +func (b *UserResourceSpecApplyConfiguration) WithPasswordRef(value apiv1alpha1.KubernetesNameRef) *UserResourceSpecApplyConfiguration { + b.PasswordRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/userresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/userresourcestatus.go new file mode 100644 index 000000000..db56adfbf --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/userresourcestatus.go @@ -0,0 +1,93 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// UserResourceStatusApplyConfiguration represents a declarative configuration of the UserResourceStatus type for use +// with apply. +type UserResourceStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + DomainID *string `json:"domainID,omitempty"` + DefaultProjectID *string `json:"defaultProjectID,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + PasswordExpiresAt *string `json:"passwordExpiresAt,omitempty"` + AppliedPasswordRef *string `json:"appliedPasswordRef,omitempty"` +} + +// UserResourceStatusApplyConfiguration constructs a declarative configuration of the UserResourceStatus type for use with +// apply. +func UserResourceStatus() *UserResourceStatusApplyConfiguration { + return &UserResourceStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *UserResourceStatusApplyConfiguration) WithName(value string) *UserResourceStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *UserResourceStatusApplyConfiguration) WithDescription(value string) *UserResourceStatusApplyConfiguration { + b.Description = &value + return b +} + +// WithDomainID sets the DomainID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DomainID field is set to the value of the last call. +func (b *UserResourceStatusApplyConfiguration) WithDomainID(value string) *UserResourceStatusApplyConfiguration { + b.DomainID = &value + return b +} + +// WithDefaultProjectID sets the DefaultProjectID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DefaultProjectID field is set to the value of the last call. +func (b *UserResourceStatusApplyConfiguration) WithDefaultProjectID(value string) *UserResourceStatusApplyConfiguration { + b.DefaultProjectID = &value + return b +} + +// WithEnabled sets the Enabled field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Enabled field is set to the value of the last call. +func (b *UserResourceStatusApplyConfiguration) WithEnabled(value bool) *UserResourceStatusApplyConfiguration { + b.Enabled = &value + return b +} + +// WithPasswordExpiresAt sets the PasswordExpiresAt field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PasswordExpiresAt field is set to the value of the last call. +func (b *UserResourceStatusApplyConfiguration) WithPasswordExpiresAt(value string) *UserResourceStatusApplyConfiguration { + b.PasswordExpiresAt = &value + return b +} + +// WithAppliedPasswordRef sets the AppliedPasswordRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the AppliedPasswordRef field is set to the value of the last call. +func (b *UserResourceStatusApplyConfiguration) WithAppliedPasswordRef(value string) *UserResourceStatusApplyConfiguration { + b.AppliedPasswordRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/userspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/userspec.go new file mode 100644 index 000000000..8ce4fb751 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/userspec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// UserSpecApplyConfiguration represents a declarative configuration of the UserSpec type for use +// with apply. +type UserSpecApplyConfiguration struct { + Import *UserImportApplyConfiguration `json:"import,omitempty"` + Resource *UserResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// UserSpecApplyConfiguration constructs a declarative configuration of the UserSpec type for use with +// apply. +func UserSpec() *UserSpecApplyConfiguration { + return &UserSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *UserSpecApplyConfiguration) WithImport(value *UserImportApplyConfiguration) *UserSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *UserSpecApplyConfiguration) WithResource(value *UserResourceSpecApplyConfiguration) *UserSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *UserSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *UserSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *UserSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *UserSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *UserSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *UserSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *UserSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *UserSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/userstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/userstatus.go new file mode 100644 index 000000000..d2e1194bf --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/userstatus.go @@ -0,0 +1,76 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// UserStatusApplyConfiguration represents a declarative configuration of the UserStatus type for use +// with apply. +type UserStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *UserResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// UserStatusApplyConfiguration constructs a declarative configuration of the UserStatus type for use with +// apply. +func UserStatus() *UserStatusApplyConfiguration { + return &UserStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *UserStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *UserStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *UserStatusApplyConfiguration) WithID(value string) *UserStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *UserStatusApplyConfiguration) WithResource(value *UserResourceStatusApplyConfiguration) *UserStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *UserStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *UserStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volume.go b/pkg/clients/applyconfiguration/api/v1alpha1/volume.go index 648631092..5dc4ae9ce 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volume.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volume.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumeattachmentstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumeattachmentstatus.go index d005148bf..bf2f8469c 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumeattachmentstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumeattachmentstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumefilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumefilter.go index cd69f5931..5f501b8f9 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumefilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumefilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumeimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumeimport.go index 2c8a4f667..0607f42e6 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumeimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumeimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadata.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadata.go index 243503205..d8a099f3a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadata.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadata.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadatastatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadatastatus.go index 680b4a38c..5791a90fd 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadatastatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumemetadatastatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcespec.go index 7386c2714..d6c7f2f04 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ type VolumeResourceSpecApplyConfiguration struct { VolumeTypeRef *apiv1alpha1.KubernetesNameRef `json:"volumeTypeRef,omitempty"` AvailabilityZone *string `json:"availabilityZone,omitempty"` Metadata []VolumeMetadataApplyConfiguration `json:"metadata,omitempty"` + ImageRef *apiv1alpha1.KubernetesNameRef `json:"imageRef,omitempty"` } // VolumeResourceSpecApplyConfiguration constructs a declarative configuration of the VolumeResourceSpec type for use with @@ -91,3 +92,11 @@ func (b *VolumeResourceSpecApplyConfiguration) WithMetadata(values ...*VolumeMet } return b } + +// WithImageRef sets the ImageRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ImageRef field is set to the value of the last call. +func (b *VolumeResourceSpecApplyConfiguration) WithImageRef(value apiv1alpha1.KubernetesNameRef) *VolumeResourceSpecApplyConfiguration { + b.ImageRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcestatus.go index d3113778e..a9eb7c404 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumeresourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ type VolumeResourceStatusApplyConfiguration struct { Metadata []VolumeMetadataStatusApplyConfiguration `json:"metadata,omitempty"` UserID *string `json:"userID,omitempty"` Bootable *bool `json:"bootable,omitempty"` + ImageID *string `json:"imageID,omitempty"` Encrypted *bool `json:"encrypted,omitempty"` ReplicationStatus *string `json:"replicationStatus,omitempty"` ConsistencyGroupID *string `json:"consistencyGroupID,omitempty"` @@ -168,6 +169,14 @@ func (b *VolumeResourceStatusApplyConfiguration) WithBootable(value bool) *Volum return b } +// WithImageID sets the ImageID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ImageID field is set to the value of the last call. +func (b *VolumeResourceStatusApplyConfiguration) WithImageID(value string) *VolumeResourceStatusApplyConfiguration { + b.ImageID = &value + return b +} + // WithEncrypted sets the Encrypted field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Encrypted field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumespec.go index 1444e10c1..208243749 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // VolumeSpecApplyConfiguration represents a declarative configuration of the VolumeSpec type for use @@ -29,6 +30,7 @@ type VolumeSpecApplyConfiguration struct { Resource *VolumeResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *VolumeSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsA return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *VolumeSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *VolumeSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumestatus.go index 6d93bb445..fb12e4acf 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // VolumeStatusApplyConfiguration represents a declarative configuration of the VolumeStatus type for use // with apply. type VolumeStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *VolumeResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *VolumeResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // VolumeStatusApplyConfiguration constructs a declarative configuration of the VolumeStatus type for use with @@ -64,3 +66,11 @@ func (b *VolumeStatusApplyConfiguration) WithResource(value *VolumeResourceStatu b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *VolumeStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *VolumeStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetype.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetype.go index baa70c6d4..67d365b19 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetype.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetype.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspec.go index 4dde7e431..bebc95ca9 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspecstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspecstatus.go index 3bec3d64e..17928fc31 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspecstatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeextraspecstatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypefilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypefilter.go index 252352714..3173d031b 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypefilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypefilter.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeimport.go index d6756b106..e228e4c2f 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeimport.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypeimport.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcespec.go index f85aef90c..88691bffb 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcestatus.go index 9550c19b5..a6e393435 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetyperesourcestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypespec.go index ee9cb26d7..42f263428 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypespec.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package v1alpha1 import ( apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // VolumeTypeSpecApplyConfiguration represents a declarative configuration of the VolumeTypeSpec type for use @@ -29,6 +30,7 @@ type VolumeTypeSpecApplyConfiguration struct { Resource *VolumeTypeResourceSpecApplyConfiguration `json:"resource,omitempty"` ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` } @@ -70,6 +72,14 @@ func (b *VolumeTypeSpecApplyConfiguration) WithManagedOptions(value *ManagedOpti return b } +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *VolumeTypeSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *VolumeTypeSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + // WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the CloudCredentialsRef field is set to the value of the last call. diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypestatus.go index 78e67a846..b54ea49fc 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/volumetypestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/volumetypestatus.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,15 +19,17 @@ limitations under the License. package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/client-go/applyconfigurations/meta/v1" ) // VolumeTypeStatusApplyConfiguration represents a declarative configuration of the VolumeTypeStatus type for use // with apply. type VolumeTypeStatusApplyConfiguration struct { - Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` - ID *string `json:"id,omitempty"` - Resource *VolumeTypeResourceStatusApplyConfiguration `json:"resource,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *VolumeTypeResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` } // VolumeTypeStatusApplyConfiguration constructs a declarative configuration of the VolumeTypeStatus type for use with @@ -64,3 +66,11 @@ func (b *VolumeTypeStatusApplyConfiguration) WithResource(value *VolumeTypeResou b.Resource = value return b } + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *VolumeTypeStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *VolumeTypeStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/internal/internal.go b/pkg/clients/applyconfiguration/internal/internal.go index 5b5cb5142..9fc18f739 100644 --- a/pkg/clients/applyconfiguration/internal/internal.go +++ b/pkg/clients/applyconfiguration/internal/internal.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -48,52 +48,7 @@ var schemaYAML = typed.YAMLObject(`types: - name: subnetRef type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPool - map: - fields: - - name: end - type: - scalar: string - - name: start - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPoolStatus - map: - fields: - - name: end - type: - scalar: string - - name: start - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPair - map: - fields: - - name: ip - type: - scalar: string - - name: mac - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPairStatus - map: - fields: - - name: ip - type: - scalar: string - - name: mac - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference - map: - fields: - - name: cloudName - type: - scalar: string - - name: secretName - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Domain +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScope map: fields: - name: apiVersion @@ -108,55 +63,68 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeFilter map: fields: - - name: enabled + - name: ipVersion type: - scalar: boolean + scalar: numeric - name: name type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainImport + - name: projectRef + type: + scalar: string + - name: shared + type: + scalar: boolean +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeResourceSpec map: fields: - - name: description - type: - scalar: string - - name: enabled + - name: ipVersion type: - scalar: boolean + scalar: numeric + default: 0 - name: name type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceStatus - map: - fields: - - name: description + - name: projectRef type: scalar: string - - name: enabled + - name: shared type: scalar: boolean +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeResourceStatus + map: + fields: + - name: ipVersion + type: + scalar: numeric - name: name type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainSpec + - name: projectID + type: + scalar: string + - name: shared + type: + scalar: boolean +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeSpec map: fields: - name: cloudCredentialsRef @@ -165,7 +133,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -174,8 +142,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeStatus map: fields: - name: conditions @@ -189,31 +160,49 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGateway + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AddressScopeResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPool map: fields: - - name: networkRef + - name: end type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGatewayStatus + - name: start + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPoolStatus map: fields: - - name: networkID + - name: end type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FixedIPStatus + - name: start + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPair map: fields: - name: ip type: scalar: string - - name: subnetID + - name: mac type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Flavor +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPairStatus + map: + fields: + - name: ip + type: + scalar: string + - name: mac + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredential map: fields: - name: apiVersion @@ -228,92 +217,136 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialAccessRule map: fields: - - name: disk + - name: method type: - scalar: numeric - - name: name + scalar: string + - name: path type: scalar: string - - name: ram + - name: serviceRef type: - scalar: numeric - - name: vcpus + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialAccessRuleStatus + map: + fields: + - name: id type: - scalar: numeric -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorImport + scalar: string + - name: method + type: + scalar: string + - name: path + type: + scalar: string + - name: service + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialFilter + map: + fields: + - name: description + type: + scalar: string + - name: name + type: + scalar: string + - name: userRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialResourceSpec map: fields: + - name: accessRules + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialAccessRule + elementRelationship: atomic - name: description type: scalar: string - - name: disk - type: - scalar: numeric - default: 0 - - name: ephemeral + - name: expiresAt type: - scalar: numeric - - name: isPublic - type: - scalar: boolean + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: name type: scalar: string - - name: ram + - name: roleRefs type: - scalar: numeric - - name: swap + list: + elementType: + scalar: string + elementRelationship: atomic + - name: secretRef type: - scalar: numeric - - name: vcpus + scalar: string + - name: unrestricted type: - scalar: numeric -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceStatus + scalar: boolean + - name: userRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialResourceStatus map: fields: + - name: accessRules + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialAccessRuleStatus + elementRelationship: atomic - name: description type: scalar: string - - name: disk + - name: expiresAt type: - scalar: numeric - - name: ephemeral + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: name type: - scalar: numeric - - name: isPublic + scalar: string + - name: projectID + type: + scalar: string + - name: roles + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialRoleStatus + elementRelationship: atomic + - name: unrestricted type: scalar: boolean - - name: name +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialRoleStatus + map: + fields: + - name: domainID type: scalar: string - - name: ram - type: - scalar: numeric - - name: swap + - name: id type: - scalar: numeric - - name: vcpus + scalar: string + - name: name type: - scalar: numeric -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorSpec + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialSpec map: fields: - name: cloudCredentialsRef @@ -322,7 +355,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -331,8 +364,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialStatus map: fields: - name: conditions @@ -346,10 +382,22 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIP + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ApplicationCredentialResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + map: + fields: + - name: cloudName + type: + scalar: string + - name: secretName + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Domain map: fields: - name: apiVersion @@ -364,142 +412,55 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainFilter map: fields: - - name: description + - name: enabled type: - scalar: string - - name: floatingIP + scalar: boolean + - name: name type: scalar: string - - name: floatingNetworkRef - type: - scalar: string - - name: notTags - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: notTagsAny - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: portRef - type: - scalar: string - - name: projectRef - type: - scalar: string - - name: status - type: - scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: tagsAny - type: - list: - elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPImport +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceSpec map: fields: - name: description type: scalar: string - - name: fixedIP - type: - scalar: string - - name: floatingIP - type: - scalar: string - - name: floatingNetworkRef - type: - scalar: string - - name: floatingSubnetRef - type: - scalar: string - - name: portRef + - name: enabled type: - scalar: string - - name: projectRef + scalar: boolean + - name: name type: scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceStatus map: fields: - - name: createdAt - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: description type: scalar: string - - name: fixedIP - type: - scalar: string - - name: floatingIP - type: - scalar: string - - name: floatingNetworkID - type: - scalar: string - - name: portID - type: - scalar: string - - name: projectID - type: - scalar: string - - name: revisionNumber - type: - scalar: numeric - - name: routerID - type: - scalar: string - - name: status - type: - scalar: string - - name: tags + - name: enabled type: - list: - elementType: - scalar: string - elementRelationship: atomic - - name: tenantID + scalar: boolean + - name: name type: scalar: string - - name: updatedAt - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainSpec map: fields: - name: cloudCredentialsRef @@ -508,7 +469,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -517,8 +478,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainStatus map: fields: - name: conditions @@ -532,10 +496,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Group + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.DomainResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Endpoint map: fields: - name: apiVersion @@ -550,55 +517,71 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointFilter map: fields: - - name: domainRef + - name: interface type: scalar: string - - name: name + - name: serviceRef type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupImport + - name: url + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointResourceSpec map: fields: - name: description type: scalar: string - - name: domainRef + - name: enabled + type: + scalar: boolean + - name: interface type: scalar: string - - name: name + - name: serviceRef type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceStatus + - name: url + type: + scalar: string + default: "" +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointResourceStatus map: fields: - name: description type: scalar: string - - name: domainID + - name: enabled + type: + scalar: boolean + - name: interface type: scalar: string - - name: name + - name: serviceID type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupSpec + - name: url + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointSpec map: fields: - name: cloudCredentialsRef @@ -607,7 +590,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -616,8 +599,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointStatus map: fields: - name: conditions @@ -631,37 +617,34 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRoute + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.EndpointResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGateway map: fields: - - name: destination - type: - scalar: string - - name: nextHop + - name: networkRef type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRouteStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGatewayStatus map: fields: - - name: destination - type: - scalar: string - - name: nextHop + - name: networkID type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.IPv6Options +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FixedIPStatus map: fields: - - name: addressMode + - name: ip type: scalar: string - - name: raMode + - name: subnetID type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Image +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Flavor map: fields: - name: apiVersion @@ -676,191 +659,129 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContent - map: - fields: - - name: containerFormat - type: - scalar: string - - name: diskFormat - type: - scalar: string - - name: download - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContentSourceDownload -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContentSourceDownload +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorExtraSpec map: fields: - - name: decompress + - name: name type: scalar: string - - name: hash - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageHash - - name: url + default: "" + - name: value type: scalar: string default: "" -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorExtraSpecStatus map: fields: - name: name type: scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: visibility + - name: value type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageHash +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorFilter map: fields: - - name: algorithm + - name: disk type: - scalar: string - - name: value + scalar: numeric + - name: name type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageImport + - name: ram + type: + scalar: numeric + - name: vcpus + type: + scalar: numeric +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageProperties +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceSpec map: fields: - - name: architecture - type: - scalar: string - - name: hardware - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesHardware - - name: hypervisorType + - name: description type: scalar: string - - name: minDiskGB + - name: disk type: scalar: numeric - - name: minMemoryMB + default: 0 + - name: ephemeral type: scalar: numeric - - name: operatingSystem - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesOperatingSystem -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesHardware - map: - fields: - - name: cdromBus - type: - scalar: string - - name: cpuCores + - name: extraSpecs type: - scalar: numeric - - name: cpuPolicy - type: - scalar: string - - name: cpuSockets - type: - scalar: numeric - - name: cpuThreadPolicy - type: - scalar: string - - name: cpuThreads - type: - scalar: numeric - - name: diskBus + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorExtraSpec + elementRelationship: associative + keys: + - name + - name: id type: scalar: string - - name: qemuGuestAgent + - name: isPublic type: scalar: boolean - - name: rngModel - type: - scalar: string - - name: scsiModel + - name: name type: scalar: string - - name: vifModel + - name: ram type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesOperatingSystem - map: - fields: - - name: distro + scalar: numeric + - name: swap type: - scalar: string - - name: version + scalar: numeric + - name: vcpus type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceSpec + scalar: numeric +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceStatus map: fields: - - name: content - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContent - - name: name + - name: description type: scalar: string - - name: properties + - name: disk type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageProperties - - name: protected + scalar: numeric + - name: ephemeral type: - scalar: boolean - - name: tags + scalar: numeric + - name: extraSpecs type: list: elementType: - scalar: string - elementRelationship: associative - - name: visibility - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceStatus - map: - fields: - - name: hash + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorExtraSpecStatus + elementRelationship: atomic + - name: isPublic type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageHash + scalar: boolean - name: name type: scalar: string - - name: protected - type: - scalar: boolean - - name: sizeB + - name: ram type: scalar: numeric - - name: status - type: - scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: atomic - - name: virtualSizeB + - name: swap type: scalar: numeric - - name: visibility + - name: vcpus type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageSpec + scalar: numeric +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorSpec map: fields: - name: cloudCredentialsRef @@ -869,7 +790,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -878,8 +799,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorStatus map: fields: - name: conditions @@ -890,16 +814,16 @@ var schemaYAML = typed.YAMLObject(`types: elementRelationship: associative keys: - type - - name: downloadAttempts - type: - scalar: numeric - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPair + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FlavorResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIP map: fields: - name: apiVersion @@ -914,55 +838,142 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPFilter map: fields: - - name: name + - name: description type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairImport + - name: floatingIP + type: + scalar: string + - name: floatingNetworkRef + type: + scalar: string + - name: notTags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: notTagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: portRef + type: + scalar: string + - name: projectRef + type: + scalar: string + - name: status + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: tagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceSpec map: fields: - - name: name + - name: description type: scalar: string - - name: publicKey + - name: fixedIP type: scalar: string - - name: type + - name: floatingIP type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceStatus + - name: floatingNetworkRef + type: + scalar: string + - name: floatingSubnetRef + type: + scalar: string + - name: portRef + type: + scalar: string + - name: projectRef + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceStatus map: fields: - - name: fingerprint + - name: createdAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: description type: scalar: string - - name: name + - name: fixedIP type: scalar: string - - name: publicKey + - name: floatingIP type: scalar: string - - name: type + - name: floatingNetworkID type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairSpec + - name: portID + type: + scalar: string + - name: projectID + type: + scalar: string + - name: revisionNumber + type: + scalar: numeric + - name: routerID + type: + scalar: string + - name: status + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: tenantID + type: + scalar: string + - name: updatedAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPSpec map: fields: - name: cloudCredentialsRef @@ -971,7 +982,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -980,8 +991,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPStatus map: fields: - name: conditions @@ -995,16 +1009,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string - - name: resource + - name: lastSyncTime type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions - map: - fields: - - name: onDelete + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Network + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FloatingIPResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Group map: fields: - name: apiVersion @@ -1019,21 +1030,1025 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupFilter map: fields: - - name: description + - name: domainRef type: scalar: string - - name: external + - name: name + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupFilter + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceSpec + map: + fields: + - name: description + type: + scalar: string + - name: domainRef + type: + scalar: string + - name: name + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceStatus + map: + fields: + - name: description + type: + scalar: string + - name: domainID + type: + scalar: string + - name: name + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy + type: + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupStatus + map: + fields: + - name: conditions + type: + list: + elementType: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.GroupResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostID + map: + fields: + - name: id + type: + scalar: string + - name: serverRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRoute + map: + fields: + - name: destination + type: + scalar: string + - name: nextHop + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRouteStatus + map: + fields: + - name: destination + type: + scalar: string + - name: nextHop + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.IPv6Options + map: + fields: + - name: addressMode + type: + scalar: string + - name: raMode + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Image + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContent + map: + fields: + - name: containerFormat + type: + scalar: string + - name: diskFormat + type: + scalar: string + - name: download + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContentSourceDownload +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContentSourceDownload + map: + fields: + - name: decompress + type: + scalar: string + - name: hash + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageHash + - name: url + type: + scalar: string + default: "" +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageFilter + map: + fields: + - name: name + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: visibility + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageHash + map: + fields: + - name: algorithm + type: + scalar: string + - name: value + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageFilter + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageProperties + map: + fields: + - name: architecture + type: + scalar: string + - name: hardware + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesHardware + - name: hypervisorType + type: + scalar: string + - name: minDiskGB + type: + scalar: numeric + - name: minMemoryMB + type: + scalar: numeric + - name: operatingSystem + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesOperatingSystem +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesHardware + map: + fields: + - name: cdromBus + type: + scalar: string + - name: cpuCores + type: + scalar: numeric + - name: cpuPolicy + type: + scalar: string + - name: cpuSockets + type: + scalar: numeric + - name: cpuThreadPolicy + type: + scalar: string + - name: cpuThreads + type: + scalar: numeric + - name: diskBus + type: + scalar: string + - name: qemuGuestAgent + type: + scalar: boolean + - name: rngModel + type: + scalar: string + - name: scsiModel + type: + scalar: string + - name: vifModel + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImagePropertiesOperatingSystem + map: + fields: + - name: distro + type: + scalar: string + - name: version + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceSpec + map: + fields: + - name: content + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageContent + - name: name + type: + scalar: string + - name: properties + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageProperties + - name: protected + type: + scalar: boolean + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: visibility + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceStatus + map: + fields: + - name: hash + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageHash + - name: name + type: + scalar: string + - name: protected + type: + scalar: boolean + - name: sizeB + type: + scalar: numeric + - name: status + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: virtualSizeB + type: + scalar: numeric + - name: visibility + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy + type: + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageStatus + map: + fields: + - name: conditions + type: + list: + elementType: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: downloadAttempts + type: + scalar: numeric + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ImageResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPair + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairFilter + map: + fields: + - name: name + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairFilter + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceSpec + map: + fields: + - name: name + type: + scalar: string + - name: publicKey + type: + scalar: string + - name: type + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceStatus + map: + fields: + - name: fingerprint + type: + scalar: string + - name: name + type: + scalar: string + - name: publicKey + type: + scalar: string + - name: type + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy + type: + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairStatus + map: + fields: + - name: conditions + type: + list: + elementType: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.KeyPairResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + map: + fields: + - name: onDelete + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Network + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkFilter + map: + fields: + - name: description + type: + scalar: string + - name: external + type: + scalar: boolean + - name: name + type: + scalar: string + - name: notTags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: notTagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: projectRef + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: tagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkFilter + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceSpec + map: + fields: + - name: adminStateUp + type: + scalar: boolean + - name: availabilityZoneHints + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: description + type: + scalar: string + - name: dnsDomain + type: + scalar: string + - name: external + type: + scalar: boolean + - name: mtu + type: + scalar: numeric + - name: name + type: + scalar: string + - name: portSecurityEnabled + type: + scalar: boolean + - name: projectRef + type: + scalar: string + - name: shared + type: + scalar: boolean + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceStatus + map: + fields: + - name: adminStateUp + type: + scalar: boolean + - name: availabilityZoneHints + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: createdAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: description + type: + scalar: string + - name: dnsDomain + type: + scalar: string + - name: external + type: + scalar: boolean + - name: mtu + type: + scalar: numeric + - name: name + type: + scalar: string + - name: portSecurityEnabled + type: + scalar: boolean + - name: projectID + type: + scalar: string + - name: provider + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProviderPropertiesStatus + - name: revisionNumber + type: + scalar: numeric + - name: shared + type: + scalar: boolean + - name: status + type: + scalar: string + - name: subnets + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: updatedAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy + type: + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkStatus + map: + fields: + - name: conditions + type: + list: + elementType: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Port + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortFilter + map: + fields: + - name: adminStateUp + type: + scalar: boolean + - name: description + type: + scalar: string + - name: macAddress + type: + scalar: string + - name: name + type: + scalar: string + - name: networkRef + type: + scalar: string + default: "" + - name: notTags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: notTagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: projectRef + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: tagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortFilter + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeSpec + map: + fields: + - name: max + type: + scalar: numeric + default: 0 + - name: min + type: + scalar: numeric + default: 0 +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeStatus + map: + fields: + - name: max + type: + scalar: numeric + default: 0 + - name: min + type: + scalar: numeric + default: 0 +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceSpec + map: + fields: + - name: addresses + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Address + elementRelationship: atomic + - name: adminStateUp + type: + scalar: boolean + - name: allowedAddressPairs + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPair + elementRelationship: atomic + - name: description + type: + scalar: string + - name: hostID + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostID + - name: macAddress + type: + scalar: string + - name: name + type: + scalar: string + - name: networkRef + type: + scalar: string + - name: portSecurity + type: + scalar: string + - name: projectRef + type: + scalar: string + - name: propagateUplinkStatus + type: + scalar: boolean + - name: securityGroupRefs + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: trustedVIF + type: + scalar: boolean + - name: valueSpecs + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortValueSpec + elementRelationship: associative + keys: + - key + - name: vnicType + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceStatus + map: + fields: + - name: adminStateUp + type: + scalar: boolean + - name: allowedAddressPairs + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPairStatus + elementRelationship: atomic + - name: createdAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: description + type: + scalar: string + - name: deviceID + type: + scalar: string + - name: deviceOwner + type: + scalar: string + - name: fixedIPs + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FixedIPStatus + elementRelationship: atomic + - name: hostID + type: + scalar: string + - name: macAddress + type: + scalar: string + - name: name + type: + scalar: string + - name: networkID + type: + scalar: string + - name: portSecurityEnabled + type: + scalar: boolean + - name: projectID + type: + scalar: string + - name: propagateUplinkStatus + type: + scalar: boolean + - name: revisionNumber + type: + scalar: numeric + - name: securityGroups + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: status + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: trustedVIF + type: + scalar: boolean + - name: updatedAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: vnicType + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy type: - scalar: boolean + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortStatus + map: + fields: + - name: conditions + type: + list: + elementType: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortValueSpec + map: + fields: + - name: key + type: + scalar: string + - name: value + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Project + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectFilter + map: + fields: + - name: domainRef + type: + scalar: string - name: name type: scalar: string @@ -1049,9 +2064,6 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative - - name: projectRef - type: - scalar: string - name: tags type: list: @@ -1064,121 +2076,295 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkImport +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceSpec map: fields: - - name: adminStateUp + - name: description + type: + scalar: string + - name: domainRef + type: + scalar: string + - name: enabled type: scalar: boolean - - name: availabilityZoneHints + - name: name + type: + scalar: string + - name: tags type: list: elementType: scalar: string elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceStatus + map: + fields: - name: description type: scalar: string - - name: dnsDomain + - name: domainID type: scalar: string - - name: external + - name: enabled type: scalar: boolean - - name: mtu - type: - scalar: numeric - name: name type: scalar: string - - name: portSecurityEnabled + - name: tags type: - scalar: boolean - - name: projectRef + list: + elementType: + scalar: string + elementRelationship: atomic +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy type: scalar: string - - name: shared + - name: resource type: - scalar: boolean - - name: tags + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectStatus + map: + fields: + - name: conditions type: list: elementType: - scalar: string + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceStatus + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProviderPropertiesStatus map: fields: - - name: adminStateUp + - name: networkType type: - scalar: boolean - - name: availabilityZoneHints + scalar: string + - name: physicalNetwork + type: + scalar: string + - name: segmentationID + type: + scalar: numeric +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Role + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignment + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentFilter + map: + fields: + - name: domainRef + type: + scalar: string + - name: groupRef + type: + scalar: string + - name: projectRef + type: + scalar: string + - name: roleRef + type: + scalar: string + - name: userRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentResourceSpec + map: + fields: + - name: domainRef + type: + scalar: string + - name: groupRef + type: + scalar: string + - name: projectRef + type: + scalar: string + - name: roleRef + type: + scalar: string + - name: userRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentResourceStatus + map: + fields: + - name: domainID + type: + scalar: string + - name: groupID + type: + scalar: string + - name: projectID + type: + scalar: string + - name: roleID + type: + scalar: string + - name: userID + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy + type: + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentStatus + map: + fields: + - name: conditions type: list: elementType: - scalar: string - elementRelationship: atomic - - name: createdAt + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: lastSyncTime type: namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - - name: description + - name: resource type: - scalar: string - - name: dnsDomain + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleAssignmentResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleFilter + map: + fields: + - name: domainRef type: scalar: string - - name: external - type: - scalar: boolean - - name: mtu - type: - scalar: numeric - name: name type: scalar: string - - name: portSecurityEnabled +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleImport + map: + fields: + - name: filter type: - scalar: boolean - - name: projectID + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleFilter + - name: id type: scalar: string - - name: provider - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProviderPropertiesStatus - - name: revisionNumber +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceSpec + map: + fields: + - name: description type: - scalar: numeric - - name: shared + scalar: string + - name: domainRef type: - scalar: boolean - - name: status + scalar: string + - name: name type: scalar: string - - name: subnets +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceStatus + map: + fields: + - name: description type: - list: - elementType: - scalar: string - elementRelationship: atomic - - name: tags + scalar: string + - name: domainID type: - list: - elementType: - scalar: string - elementRelationship: atomic - - name: updatedAt + scalar: string + - name: name type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkSpec + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleSpec map: fields: - name: cloudCredentialsRef @@ -1187,7 +2373,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -1196,8 +2382,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleStatus map: fields: - name: conditions @@ -1211,10 +2400,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.NetworkResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Port + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Router map: fields: - name: apiVersion @@ -1229,28 +2421,21 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterFilter map: fields: - - name: adminStateUp - type: - scalar: boolean - name: description type: scalar: string - name: name type: scalar: string - - name: networkRef - type: - scalar: string - default: "" - name: notTags type: list: @@ -1278,142 +2463,131 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortImport +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterface map: fields: - - name: max + - name: apiVersion type: - scalar: numeric - default: 0 - - name: min + scalar: string + - name: kind type: - scalar: numeric - default: 0 -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeStatus + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceSpec map: fields: - - name: max + - name: resyncPeriod type: - scalar: numeric - default: 0 - - name: min + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration + - name: routerRef type: - scalar: numeric - default: 0 -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceSpec + scalar: string + - name: subnetRef + type: + scalar: string + - name: type + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceStatus map: fields: - - name: addresses + - name: conditions type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Address - elementRelationship: atomic + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceSpec + map: + fields: - name: adminStateUp type: scalar: boolean - - name: allowedAddressPairs + - name: availabilityZoneHints type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPair - elementRelationship: atomic + scalar: string + elementRelationship: associative - name: description type: scalar: string - - name: name + - name: distributed type: - scalar: string - - name: networkRef + scalar: boolean + - name: externalGateways type: - scalar: string - - name: portSecurity + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGateway + elementRelationship: atomic + - name: name type: scalar: string - name: projectRef type: scalar: string - - name: securityGroupRefs - type: - list: - elementType: - scalar: string - elementRelationship: associative - name: tags type: list: elementType: scalar: string elementRelationship: associative - - name: vnicType - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceStatus map: fields: - name: adminStateUp type: scalar: boolean - - name: allowedAddressPairs + - name: availabilityZoneHints type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllowedAddressPairStatus + scalar: string elementRelationship: atomic - - name: createdAt - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: description type: scalar: string - - name: deviceID - type: - scalar: string - - name: deviceOwner - type: - scalar: string - - name: fixedIPs + - name: externalGateways type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.FixedIPStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGatewayStatus elementRelationship: atomic - - name: macAddress - type: - scalar: string - name: name type: scalar: string - - name: networkID - type: - scalar: string - - name: portSecurityEnabled - type: - scalar: boolean - name: projectID type: scalar: string - - name: propagateUplinkStatus - type: - scalar: boolean - - name: revisionNumber - type: - scalar: numeric - - name: securityGroups - type: - list: - elementType: - scalar: string - elementRelationship: atomic - name: status type: scalar: string @@ -1423,13 +2597,7 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: atomic - - name: updatedAt - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - - name: vnicType - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterSpec map: fields: - name: cloudCredentialsRef @@ -1438,7 +2606,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -1447,8 +2615,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterStatus map: fields: - name: conditions @@ -1462,10 +2633,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Project + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroup map: fields: - name: apiVersion @@ -1480,15 +2654,18 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupFilter map: fields: + - name: description + type: + scalar: string - name: name type: scalar: string @@ -1504,6 +2681,9 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative + - name: projectRef + type: + scalar: string - name: tags type: list: @@ -1516,163 +2696,127 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectImport +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceSpec map: fields: - name: description type: scalar: string - - name: enabled - type: - scalar: boolean - name: name type: scalar: string - - name: tags + - name: projectRef + type: + scalar: string + - name: rules type: list: elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceStatus - map: - fields: - - name: description - type: - scalar: string - - name: enabled + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRule + elementRelationship: atomic + - name: stateful type: scalar: boolean - - name: name - type: - scalar: string - name: tags type: list: elementType: scalar: string - elementRelationship: atomic -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectSpec + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceStatus map: fields: - - name: cloudCredentialsRef + - name: createdAt type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference - default: {} - - name: import + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: description type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectImport - - name: managedOptions + scalar: string + - name: name type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions - - name: managementPolicy + scalar: string + - name: projectID type: scalar: string - - name: resource + - name: revisionNumber type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectStatus - map: - fields: - - name: conditions + scalar: numeric + - name: rules type: list: elementType: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition - elementRelationship: associative - keys: - - type - - name: id - type: - scalar: string - - name: resource - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProjectResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ProviderPropertiesStatus - map: - fields: - - name: networkType + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRuleStatus + elementRelationship: atomic + - name: stateful type: - scalar: string - - name: physicalNetwork + scalar: boolean + - name: tags type: - scalar: string - - name: segmentationID + list: + elementType: + scalar: string + elementRelationship: atomic + - name: updatedAt type: - scalar: numeric -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Role + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRule map: fields: - - name: apiVersion + - name: description type: scalar: string - - name: kind + - name: direction type: scalar: string - - name: metadata - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta - default: {} - - name: spec + - name: ethertype type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleSpec - default: {} - - name: status + scalar: string + - name: portRange type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleStatus - default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleFilter - map: - fields: - - name: domainRef + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeSpec + - name: protocol type: scalar: string - - name: name + - name: remoteIPPrefix type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleImport +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRuleStatus map: fields: - - name: filter - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleFilter - - name: id + - name: description type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceSpec - map: - fields: - - name: description + - name: direction type: scalar: string - - name: domainRef + - name: ethertype type: scalar: string - - name: name + - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceStatus - map: - fields: - - name: description + - name: portRange + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeStatus + - name: protocol type: scalar: string - - name: domainID + - name: remoteGroupID type: scalar: string - - name: name + - name: remoteIPPrefix type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupSpec map: fields: - name: cloudCredentialsRef @@ -1681,7 +2825,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -1690,8 +2834,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupStatus map: fields: - name: conditions @@ -1705,10 +2852,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RoleResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Router + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Server map: fields: - name: apiVersion @@ -1723,16 +2873,25 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerBootVolumeSpec map: fields: - - name: description + - name: tag + type: + scalar: string + - name: volumeRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerFilter + map: + fields: + - name: availabilityZone type: scalar: string - name: name @@ -1750,9 +2909,6 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative - - name: projectRef - type: - scalar: string - name: tags type: list: @@ -1765,16 +2921,7 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterImport - map: - fields: - - name: filter - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterFilter - - name: id - type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterface +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroup map: fields: - name: apiVersion @@ -1789,111 +2936,70 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupFilter map: fields: - - name: routerRef - type: - scalar: string - - name: subnetRef - type: - scalar: string - - name: type + - name: name type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterInterfaceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupImport map: fields: - - name: conditions + - name: filter type: - list: - elementType: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition - elementRelationship: associative - keys: - - type + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceSpec - map: - fields: - - name: adminStateUp - type: - scalar: boolean - - name: availabilityZoneHints - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: description - type: - scalar: string - - name: distributed - type: - scalar: boolean - - name: externalGateways - type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGateway - elementRelationship: atomic - - name: name - type: - scalar: string - - name: projectRef - type: - scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceSpec map: - fields: - - name: adminStateUp - type: - scalar: boolean - - name: availabilityZoneHints + fields: + - name: name type: - list: - elementType: - scalar: string - elementRelationship: atomic - - name: description + scalar: string + - name: policy type: scalar: string - - name: externalGateways + - name: rules type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ExternalGatewayStatus - elementRelationship: atomic + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRules +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceStatus + map: + fields: - name: name type: scalar: string + - name: policy + type: + scalar: string - name: projectID type: scalar: string - - name: status + - name: rules + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRulesStatus + - name: userID type: scalar: string - - name: tags +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRules + map: + fields: + - name: maxServerPerHost type: - list: - elementType: - scalar: string - elementRelationship: atomic -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterSpec + scalar: numeric +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRulesStatus + map: + fields: + - name: maxServerPerHost + type: + scalar: numeric +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupSpec map: fields: - name: cloudCredentialsRef @@ -1902,7 +3008,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -1911,8 +3017,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupStatus map: fields: - name: conditions @@ -1926,187 +3035,219 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RouterResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroup + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerImport map: fields: - - name: apiVersion + - name: filter type: - scalar: string - - name: kind + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerFilter + - name: id type: scalar: string - - name: metadata - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta - default: {} - - name: spec - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupSpec - default: {} - - name: status - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupStatus - default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceFixedIP map: fields: - - name: description + - name: ipAddress type: scalar: string - - name: name + - name: subnetID type: scalar: string - - name: notTags +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceStatus + map: + fields: + - name: fixedIPs type: list: elementType: - scalar: string - elementRelationship: associative - - name: notTagsAny + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceFixedIP + elementRelationship: atomic + - name: macAddr type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: projectRef + scalar: string + - name: netID type: scalar: string - - name: tags + - name: portID type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: tagsAny + scalar: string + - name: portState type: - list: - elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupImport + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerMetadata map: fields: - - name: filter + - name: key type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupFilter - - name: id + scalar: string + - name: value type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerMetadataStatus map: fields: - - name: description + - name: key type: scalar: string - - name: name + - name: value type: scalar: string - - name: projectRef +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerPortSpec + map: + fields: + - name: portRef type: scalar: string - - name: rules - type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRule - elementRelationship: atomic - - name: stateful - type: - scalar: boolean - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceSpec map: fields: - - name: createdAt + - name: availabilityZone type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - - name: description + scalar: string + - name: bootVolume + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerBootVolumeSpec + - name: configDrive + type: + scalar: boolean + - name: flavorRef type: scalar: string - - name: name + - name: imageRef type: scalar: string - - name: projectID + - name: keypairRef type: scalar: string - - name: revisionNumber + - name: metadata type: - scalar: numeric - - name: rules + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerMetadata + elementRelationship: atomic + - name: name + type: + scalar: string + - name: ports type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRuleStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerPortSpec elementRelationship: atomic - - name: stateful + - name: schedulerHints type: - scalar: boolean + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerSchedulerHints - name: tags type: list: elementType: scalar: string - elementRelationship: atomic - - name: updatedAt + elementRelationship: associative + - name: userData type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRule + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserDataSpec + - name: volumes + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeSpec + elementRelationship: atomic +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceStatus map: fields: - - name: description + - name: availabilityZone type: scalar: string - - name: direction + - name: configDrive + type: + scalar: boolean + - name: hostID type: scalar: string - - name: ethertype + - name: imageID type: scalar: string - - name: portRange + - name: interfaces type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeSpec - - name: protocol + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceStatus + elementRelationship: atomic + - name: metadata + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerMetadataStatus + elementRelationship: atomic + - name: name type: scalar: string - - name: remoteIPPrefix + - name: serverGroups + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: status type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupRuleStatus + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: volumes + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeStatus + elementRelationship: atomic +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerSchedulerHints map: fields: - - name: description + - name: additionalProperties type: - scalar: string - - name: direction - type: - scalar: string - - name: ethertype + map: + elementType: + scalar: string + - name: buildNearHostIP type: scalar: string - - name: id + - name: differentCell type: - scalar: string - - name: portRange + list: + elementType: + scalar: string + elementRelationship: associative + - name: differentHostServerRefs type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.PortRangeStatus - - name: protocol + list: + elementType: + scalar: string + elementRelationship: associative + - name: query type: scalar: string - - name: remoteGroupID + - name: sameHostServerRefs + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: serverGroupRef type: scalar: string - - name: remoteIPPrefix + - name: targetCell type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerSpec map: fields: - name: cloudCredentialsRef @@ -2115,7 +3256,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -2124,8 +3265,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerStatus map: fields: - name: conditions @@ -2139,10 +3283,28 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SecurityGroupResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Server + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeSpec + map: + fields: + - name: device + type: + scalar: string + - name: volumeRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeStatus + map: + fields: + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Service map: fields: - name: apiVersion @@ -2157,46 +3319,103 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceFilter map: fields: - - name: availabilityZone + - name: name + type: + scalar: string + - name: type + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceFilter + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceSpec + map: + fields: + - name: description + type: + scalar: string + - name: enabled + type: + scalar: boolean + - name: name + type: + scalar: string + - name: type + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceStatus + map: + fields: + - name: description type: scalar: string + - name: enabled + type: + scalar: boolean - name: name type: scalar: string - - name: notTags + - name: type type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: notTagsAny + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceSpec + map: + fields: + - name: cloudCredentialsRef type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: tags + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: tagsAny + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy + type: + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceStatus + map: + fields: + - name: conditions type: list: elementType: - scalar: string + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroup + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetwork map: fields: - name: apiVersion @@ -2211,70 +3430,83 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkFilter map: fields: + - name: description + type: + scalar: string - name: name type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupImport +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkResourceSpec map: fields: + - name: description + type: + scalar: string - name: name type: scalar: string - - name: policy + - name: networkRef type: scalar: string - - name: rules + - name: subnetRef type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRules -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceStatus + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkResourceStatus map: fields: + - name: cidr + type: + scalar: string + default: "" + - name: createdAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: description + type: + scalar: string + - name: ipVersion + type: + scalar: numeric - name: name type: scalar: string - - name: policy + - name: networkType type: scalar: string - - name: projectID + - name: neutronNetID type: scalar: string - - name: rules + - name: neutronSubnetID type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRulesStatus - - name: userID + scalar: string + - name: projectID type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRules - map: - fields: - - name: maxServerPerHost + - name: segmentationID type: scalar: numeric -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupRulesStatus - map: - fields: - - name: maxServerPerHost + - name: updatedAt type: - scalar: numeric -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupSpec + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkSpec map: fields: - name: cloudCredentialsRef @@ -2283,7 +3515,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -2292,8 +3524,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkStatus map: fields: - name: conditions @@ -2307,79 +3542,156 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerGroupResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ShareNetworkResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Subnet + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetFilter + map: + fields: + - name: cidr + type: + scalar: string + - name: description + type: + scalar: string + - name: gatewayIP + type: + scalar: string + - name: ipVersion + type: + scalar: numeric + - name: ipv6 + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.IPv6Options + - name: name + type: + scalar: string + - name: networkRef + type: + scalar: string + default: "" + - name: notTags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: notTagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: projectRef + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: tagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetGateway map: fields: - - name: filter + - name: ip type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerFilter - - name: id + scalar: string + - name: type type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceFixedIP +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetImport map: fields: - - name: ipAddress + - name: filter type: - scalar: string - - name: subnetID + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetFilter + - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceSpec map: fields: - - name: fixedIPs + - name: allocationPools type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceFixedIP + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPool elementRelationship: atomic - - name: macAddr + - name: cidr type: scalar: string - - name: netID + - name: description type: scalar: string - - name: portID + - name: dnsNameservers type: - scalar: string - - name: portState + list: + elementType: + scalar: string + elementRelationship: associative + - name: dnsPublishFixedIP type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerPortSpec - map: - fields: - - name: portRef + scalar: boolean + - name: enableDHCP type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceSpec - map: - fields: - - name: availabilityZone + scalar: boolean + - name: gateway type: - scalar: string - - name: flavorRef + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetGateway + - name: hostRoutes type: - scalar: string - - name: imageRef + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRoute + elementRelationship: atomic + - name: ipVersion type: - scalar: string - - name: keypairRef + scalar: numeric + default: 0 + - name: ipv6 type: - scalar: string + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.IPv6Options - name: name type: scalar: string - - name: ports + - name: networkRef type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerPortSpec - elementRelationship: atomic - - name: serverGroupRef + scalar: string + - name: projectRef + type: + scalar: string + - name: routerRef type: scalar: string - name: tags @@ -2388,43 +3700,67 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: associative - - name: userData - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserDataSpec - - name: volumes +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceStatus + map: + fields: + - name: allocationPools type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPoolStatus elementRelationship: atomic -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceStatus - map: - fields: - - name: availabilityZone + - name: cidr type: scalar: string - - name: hostID + - name: createdAt type: - scalar: string - - name: imageID + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: description type: scalar: string - - name: interfaces + - name: dnsNameservers type: list: elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerInterfaceStatus + scalar: string elementRelationship: atomic - - name: name + - name: dnsPublishFixedIP + type: + scalar: boolean + - name: enableDHCP + type: + scalar: boolean + - name: gatewayIP type: scalar: string - - name: serverGroups + - name: hostRoutes type: list: elementType: - scalar: string + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRouteStatus elementRelationship: atomic - - name: status + - name: ipVersion + type: + scalar: numeric + - name: ipv6AddressMode + type: + scalar: string + - name: ipv6RAMode + type: + scalar: string + - name: name + type: + scalar: string + - name: networkID + type: + scalar: string + - name: projectID + type: + scalar: string + - name: revisionNumber + type: + scalar: numeric + - name: subnetPoolID type: scalar: string - name: tags @@ -2433,13 +3769,10 @@ var schemaYAML = typed.YAMLObject(`types: elementType: scalar: string elementRelationship: atomic - - name: volumes + - name: updatedAt type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeStatus - elementRelationship: atomic -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerSpec + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetSpec map: fields: - name: cloudCredentialsRef @@ -2448,7 +3781,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -2457,8 +3790,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetStatus map: fields: - name: conditions @@ -2472,25 +3808,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string - - name: resource - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeSpec - map: - fields: - - name: device - type: - scalar: string - - name: volumeRef + - name: lastSyncTime type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServerVolumeStatus - map: - fields: - - name: id + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource type: - scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Service + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Trunk map: fields: - name: apiVersion @@ -2505,61 +3829,139 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkFilter map: fields: + - name: adminStateUp + type: + scalar: boolean + - name: description + type: + scalar: string - name: name type: scalar: string - - name: type + - name: notTags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: notTagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: portRef type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceImport + - name: projectRef + type: + scalar: string + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: tagsAny + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkResourceSpec + map: + fields: + - name: adminStateUp + type: + scalar: boolean + - name: description + type: + scalar: string + - name: name + type: + scalar: string + - name: portRef + type: + scalar: string + - name: projectRef + type: + scalar: string + - name: subports + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkSubportSpec + elementRelationship: atomic + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: associative +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkResourceStatus map: fields: + - name: adminStateUp + type: + scalar: boolean + - name: createdAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: description type: scalar: string - - name: enabled - type: - scalar: boolean - name: name type: scalar: string - - name: type + - name: portID type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceStatus - map: - fields: - - name: description + - name: projectID type: scalar: string - - name: enabled + - name: revisionNumber type: - scalar: boolean - - name: name + scalar: numeric + - name: status type: scalar: string - - name: type + - name: subports + type: + list: + elementType: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkSubportStatus + elementRelationship: atomic + - name: tags + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: tenantID type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceSpec + - name: updatedAt + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkSpec map: fields: - name: cloudCredentialsRef @@ -2568,7 +3970,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -2577,8 +3979,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkStatus map: fields: - name: conditions @@ -2592,10 +3997,37 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ServiceResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Subnet + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkSubportSpec + map: + fields: + - name: portRef + type: + scalar: string + - name: segmentationID + type: + scalar: numeric + - name: segmentationType + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.TrunkSubportStatus + map: + fields: + - name: portID + type: + scalar: string + - name: segmentationID + type: + scalar: numeric + - name: segmentationType + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.User map: fields: - name: apiVersion @@ -2610,216 +4042,82 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: spec type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetSpec + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserSpec default: {} - name: status type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserStatus default: {} -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetFilter +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserDataSpec map: fields: - - name: cidr - type: - scalar: string - - name: description - type: - scalar: string - - name: gatewayIP - type: - scalar: string - - name: ipVersion - type: - scalar: numeric - - name: ipv6 - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.IPv6Options - - name: name - type: - scalar: string - - name: networkRef - type: - scalar: string - default: "" - - name: notTags - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: notTagsAny - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: projectRef + - name: secretRef type: scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: tagsAny - type: - list: - elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetGateway +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserFilter map: fields: - - name: ip + - name: domainRef type: scalar: string - - name: type + - name: name type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetImport +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserImport map: fields: - name: filter type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetFilter + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserFilter - name: id type: scalar: string -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserResourceSpec map: fields: - - name: allocationPools - type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPool - elementRelationship: atomic - - name: cidr + - name: defaultProjectRef type: scalar: string - name: description type: scalar: string - - name: dnsNameservers - type: - list: - elementType: - scalar: string - elementRelationship: associative - - name: dnsPublishFixedIP + - name: domainRef type: - scalar: boolean - - name: enableDHCP + scalar: string + - name: enabled type: scalar: boolean - - name: gateway - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetGateway - - name: hostRoutes - type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRoute - elementRelationship: atomic - - name: ipVersion - type: - scalar: numeric - default: 0 - - name: ipv6 - type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.IPv6Options - name: name type: scalar: string - - name: networkRef - type: - scalar: string - - name: projectRef - type: - scalar: string - - name: routerRef + - name: passwordRef type: scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: associative -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceStatus +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserResourceStatus map: fields: - - name: allocationPools - type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.AllocationPoolStatus - elementRelationship: atomic - - name: cidr + - name: appliedPasswordRef type: scalar: string - - name: createdAt - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - - name: description + - name: defaultProjectID type: scalar: string - - name: dnsNameservers - type: - list: - elementType: - scalar: string - elementRelationship: atomic - - name: dnsPublishFixedIP - type: - scalar: boolean - - name: enableDHCP - type: - scalar: boolean - - name: gatewayIP + - name: description type: scalar: string - - name: hostRoutes - type: - list: - elementType: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.HostRouteStatus - elementRelationship: atomic - - name: ipVersion - type: - scalar: numeric - - name: ipv6AddressMode + - name: domainID type: scalar: string - - name: ipv6RAMode + - name: enabled type: - scalar: string + scalar: boolean - name: name type: scalar: string - - name: networkID - type: - scalar: string - - name: projectID - type: - scalar: string - - name: revisionNumber - type: - scalar: numeric - - name: subnetPoolID + - name: passwordExpiresAt type: scalar: string - - name: tags - type: - list: - elementType: - scalar: string - elementRelationship: atomic - - name: updatedAt - type: - namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetSpec +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserSpec map: fields: - name: cloudCredentialsRef @@ -2828,7 +4126,7 @@ var schemaYAML = typed.YAMLObject(`types: default: {} - name: import type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetImport + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserImport - name: managedOptions type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions @@ -2837,8 +4135,11 @@ var schemaYAML = typed.YAMLObject(`types: scalar: string - name: resource type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceSpec -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetStatus + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserStatus map: fields: - name: conditions @@ -2852,15 +4153,12 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string - - name: resource + - name: lastSyncTime type: - namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceStatus -- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserDataSpec - map: - fields: - - name: secretRef + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource type: - scalar: string + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.UserResourceStatus - name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Volume map: fields: @@ -2953,6 +4251,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: description type: scalar: string + - name: imageRef + type: + scalar: string - name: metadata type: list: @@ -3001,6 +4302,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: host type: scalar: string + - name: imageID + type: + scalar: string - name: metadata type: list: @@ -3059,6 +4363,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: resource type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.VolumeResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration - name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.VolumeStatus map: fields: @@ -3073,6 +4380,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.VolumeResourceStatus @@ -3193,6 +4503,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: resource type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.VolumeTypeResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration - name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.VolumeTypeStatus map: fields: @@ -3207,6 +4520,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: id type: scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time - name: resource type: namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.VolumeTypeResourceStatus @@ -3235,6 +4551,8 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: string default: "" +- name: io.k8s.apimachinery.pkg.apis.meta.v1.Duration + scalar: string - name: io.k8s.apimachinery.pkg.apis.meta.v1.FieldsV1 map: elementType: diff --git a/pkg/clients/applyconfiguration/utils.go b/pkg/clients/applyconfiguration/utils.go index e3166fefe..22e66aea0 100644 --- a/pkg/clients/applyconfiguration/utils.go +++ b/pkg/clients/applyconfiguration/utils.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,6 +34,20 @@ func ForKind(kind schema.GroupVersionKind) interface{} { // Group=openstack.k-orc.cloud, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithKind("Address"): return &apiv1alpha1.AddressApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AddressScope"): + return &apiv1alpha1.AddressScopeApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AddressScopeFilter"): + return &apiv1alpha1.AddressScopeFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AddressScopeImport"): + return &apiv1alpha1.AddressScopeImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AddressScopeResourceSpec"): + return &apiv1alpha1.AddressScopeResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AddressScopeResourceStatus"): + return &apiv1alpha1.AddressScopeResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AddressScopeSpec"): + return &apiv1alpha1.AddressScopeSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("AddressScopeStatus"): + return &apiv1alpha1.AddressScopeStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("AllocationPool"): return &apiv1alpha1.AllocationPoolApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("AllocationPoolStatus"): @@ -42,6 +56,26 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.AllowedAddressPairApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("AllowedAddressPairStatus"): return &apiv1alpha1.AllowedAddressPairStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredential"): + return &apiv1alpha1.ApplicationCredentialApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialAccessRule"): + return &apiv1alpha1.ApplicationCredentialAccessRuleApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialAccessRuleStatus"): + return &apiv1alpha1.ApplicationCredentialAccessRuleStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialFilter"): + return &apiv1alpha1.ApplicationCredentialFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialImport"): + return &apiv1alpha1.ApplicationCredentialImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialResourceSpec"): + return &apiv1alpha1.ApplicationCredentialResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialResourceStatus"): + return &apiv1alpha1.ApplicationCredentialResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialRoleStatus"): + return &apiv1alpha1.ApplicationCredentialRoleStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialSpec"): + return &apiv1alpha1.ApplicationCredentialSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredentialStatus"): + return &apiv1alpha1.ApplicationCredentialStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("CloudCredentialsReference"): return &apiv1alpha1.CloudCredentialsReferenceApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Domain"): @@ -58,6 +92,20 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.DomainSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("DomainStatus"): return &apiv1alpha1.DomainStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("Endpoint"): + return &apiv1alpha1.EndpointApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("EndpointFilter"): + return &apiv1alpha1.EndpointFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("EndpointImport"): + return &apiv1alpha1.EndpointImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("EndpointResourceSpec"): + return &apiv1alpha1.EndpointResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("EndpointResourceStatus"): + return &apiv1alpha1.EndpointResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("EndpointSpec"): + return &apiv1alpha1.EndpointSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("EndpointStatus"): + return &apiv1alpha1.EndpointStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ExternalGateway"): return &apiv1alpha1.ExternalGatewayApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ExternalGatewayStatus"): @@ -72,6 +120,10 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.FixedIPStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Flavor"): return &apiv1alpha1.FlavorApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("FlavorExtraSpec"): + return &apiv1alpha1.FlavorExtraSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("FlavorExtraSpecStatus"): + return &apiv1alpha1.FlavorExtraSpecStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("FlavorFilter"): return &apiv1alpha1.FlavorFilterApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("FlavorImport"): @@ -112,6 +164,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.GroupSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("GroupStatus"): return &apiv1alpha1.GroupStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("HostID"): + return &apiv1alpha1.HostIDApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("HostRoute"): return &apiv1alpha1.HostRouteApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("HostRouteStatus"): @@ -196,6 +250,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.PortSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("PortStatus"): return &apiv1alpha1.PortStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("PortValueSpec"): + return &apiv1alpha1.PortValueSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Project"): return &apiv1alpha1.ProjectApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ProjectFilter"): @@ -214,6 +270,20 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.ProviderPropertiesStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Role"): return &apiv1alpha1.RoleApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignment"): + return &apiv1alpha1.RoleAssignmentApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignmentFilter"): + return &apiv1alpha1.RoleAssignmentFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignmentImport"): + return &apiv1alpha1.RoleAssignmentImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignmentResourceSpec"): + return &apiv1alpha1.RoleAssignmentResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignmentResourceStatus"): + return &apiv1alpha1.RoleAssignmentResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignmentSpec"): + return &apiv1alpha1.RoleAssignmentSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignmentStatus"): + return &apiv1alpha1.RoleAssignmentStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("RoleFilter"): return &apiv1alpha1.RoleFilterApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("RoleImport"): @@ -266,6 +336,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.SecurityGroupStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Server"): return &apiv1alpha1.ServerApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ServerBootVolumeSpec"): + return &apiv1alpha1.ServerBootVolumeSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerFilter"): return &apiv1alpha1.ServerFilterApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerGroup"): @@ -292,12 +364,18 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.ServerInterfaceFixedIPApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerInterfaceStatus"): return &apiv1alpha1.ServerInterfaceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ServerMetadata"): + return &apiv1alpha1.ServerMetadataApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ServerMetadataStatus"): + return &apiv1alpha1.ServerMetadataStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerPortSpec"): return &apiv1alpha1.ServerPortSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerResourceSpec"): return &apiv1alpha1.ServerResourceSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerResourceStatus"): return &apiv1alpha1.ServerResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ServerSchedulerHints"): + return &apiv1alpha1.ServerSchedulerHintsApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerSpec"): return &apiv1alpha1.ServerSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServerStatus"): @@ -320,6 +398,20 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.ServiceSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ServiceStatus"): return &apiv1alpha1.ServiceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ShareNetwork"): + return &apiv1alpha1.ShareNetworkApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ShareNetworkFilter"): + return &apiv1alpha1.ShareNetworkFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ShareNetworkImport"): + return &apiv1alpha1.ShareNetworkImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ShareNetworkResourceSpec"): + return &apiv1alpha1.ShareNetworkResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ShareNetworkResourceStatus"): + return &apiv1alpha1.ShareNetworkResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ShareNetworkSpec"): + return &apiv1alpha1.ShareNetworkSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ShareNetworkStatus"): + return &apiv1alpha1.ShareNetworkStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Subnet"): return &apiv1alpha1.SubnetApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("SubnetFilter"): @@ -336,8 +428,40 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.SubnetSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("SubnetStatus"): return &apiv1alpha1.SubnetStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("Trunk"): + return &apiv1alpha1.TrunkApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkFilter"): + return &apiv1alpha1.TrunkFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkImport"): + return &apiv1alpha1.TrunkImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkResourceSpec"): + return &apiv1alpha1.TrunkResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkResourceStatus"): + return &apiv1alpha1.TrunkResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkSpec"): + return &apiv1alpha1.TrunkSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkStatus"): + return &apiv1alpha1.TrunkStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkSubportSpec"): + return &apiv1alpha1.TrunkSubportSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TrunkSubportStatus"): + return &apiv1alpha1.TrunkSubportStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("User"): + return &apiv1alpha1.UserApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("UserDataSpec"): return &apiv1alpha1.UserDataSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("UserFilter"): + return &apiv1alpha1.UserFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("UserImport"): + return &apiv1alpha1.UserImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("UserResourceSpec"): + return &apiv1alpha1.UserResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("UserResourceStatus"): + return &apiv1alpha1.UserResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("UserSpec"): + return &apiv1alpha1.UserSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("UserStatus"): + return &apiv1alpha1.UserStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Volume"): return &apiv1alpha1.VolumeApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("VolumeAttachmentStatus"): diff --git a/pkg/clients/clientset/clientset/clientset.go b/pkg/clients/clientset/clientset/clientset.go index 5dc724996..a0302397c 100644 --- a/pkg/clients/clientset/clientset/clientset.go +++ b/pkg/clients/clientset/clientset/clientset.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/fake/clientset_generated.go b/pkg/clients/clientset/clientset/fake/clientset_generated.go index 39bf8513e..042753987 100644 --- a/pkg/clients/clientset/clientset/fake/clientset_generated.go +++ b/pkg/clients/clientset/clientset/fake/clientset_generated.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/fake/doc.go b/pkg/clients/clientset/clientset/fake/doc.go index 089f28395..5b176fb04 100644 --- a/pkg/clients/clientset/clientset/fake/doc.go +++ b/pkg/clients/clientset/clientset/fake/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/fake/register.go b/pkg/clients/clientset/clientset/fake/register.go index 69e224215..3c6caad14 100644 --- a/pkg/clients/clientset/clientset/fake/register.go +++ b/pkg/clients/clientset/clientset/fake/register.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/scheme/doc.go b/pkg/clients/clientset/clientset/scheme/doc.go index 959b8b28d..955d36bd2 100644 --- a/pkg/clients/clientset/clientset/scheme/doc.go +++ b/pkg/clients/clientset/clientset/scheme/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/scheme/register.go b/pkg/clients/clientset/clientset/scheme/register.go index 37f2ae0a4..333c2c424 100644 --- a/pkg/clients/clientset/clientset/scheme/register.go +++ b/pkg/clients/clientset/clientset/scheme/register.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/addressscope.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/addressscope.go new file mode 100644 index 000000000..463d3a12c --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/addressscope.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// AddressScopesGetter has a method to return a AddressScopeInterface. +// A group's client should implement this interface. +type AddressScopesGetter interface { + AddressScopes(namespace string) AddressScopeInterface +} + +// AddressScopeInterface has methods to work with AddressScope resources. +type AddressScopeInterface interface { + Create(ctx context.Context, addressScope *apiv1alpha1.AddressScope, opts v1.CreateOptions) (*apiv1alpha1.AddressScope, error) + Update(ctx context.Context, addressScope *apiv1alpha1.AddressScope, opts v1.UpdateOptions) (*apiv1alpha1.AddressScope, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, addressScope *apiv1alpha1.AddressScope, opts v1.UpdateOptions) (*apiv1alpha1.AddressScope, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.AddressScope, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.AddressScopeList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.AddressScope, err error) + Apply(ctx context.Context, addressScope *applyconfigurationapiv1alpha1.AddressScopeApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.AddressScope, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, addressScope *applyconfigurationapiv1alpha1.AddressScopeApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.AddressScope, err error) + AddressScopeExpansion +} + +// addressScopes implements AddressScopeInterface +type addressScopes struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.AddressScope, *apiv1alpha1.AddressScopeList, *applyconfigurationapiv1alpha1.AddressScopeApplyConfiguration] +} + +// newAddressScopes returns a AddressScopes +func newAddressScopes(c *OpenstackV1alpha1Client, namespace string) *addressScopes { + return &addressScopes{ + gentype.NewClientWithListAndApply[*apiv1alpha1.AddressScope, *apiv1alpha1.AddressScopeList, *applyconfigurationapiv1alpha1.AddressScopeApplyConfiguration]( + "addressscopes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.AddressScope { return &apiv1alpha1.AddressScope{} }, + func() *apiv1alpha1.AddressScopeList { return &apiv1alpha1.AddressScopeList{} }, + ), + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go index 4d2f93b0d..e39fc5dc9 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,7 +28,10 @@ import ( type OpenstackV1alpha1Interface interface { RESTClient() rest.Interface + AddressScopesGetter + ApplicationCredentialsGetter DomainsGetter + EndpointsGetter FlavorsGetter FloatingIPsGetter GroupsGetter @@ -38,13 +41,17 @@ type OpenstackV1alpha1Interface interface { PortsGetter ProjectsGetter RolesGetter + RoleAssignmentsGetter RoutersGetter RouterInterfacesGetter SecurityGroupsGetter ServersGetter ServerGroupsGetter ServicesGetter + ShareNetworksGetter SubnetsGetter + TrunksGetter + UsersGetter VolumesGetter VolumeTypesGetter } @@ -54,10 +61,22 @@ type OpenstackV1alpha1Client struct { restClient rest.Interface } +func (c *OpenstackV1alpha1Client) AddressScopes(namespace string) AddressScopeInterface { + return newAddressScopes(c, namespace) +} + +func (c *OpenstackV1alpha1Client) ApplicationCredentials(namespace string) ApplicationCredentialInterface { + return newApplicationCredentials(c, namespace) +} + func (c *OpenstackV1alpha1Client) Domains(namespace string) DomainInterface { return newDomains(c, namespace) } +func (c *OpenstackV1alpha1Client) Endpoints(namespace string) EndpointInterface { + return newEndpoints(c, namespace) +} + func (c *OpenstackV1alpha1Client) Flavors(namespace string) FlavorInterface { return newFlavors(c, namespace) } @@ -94,6 +113,10 @@ func (c *OpenstackV1alpha1Client) Roles(namespace string) RoleInterface { return newRoles(c, namespace) } +func (c *OpenstackV1alpha1Client) RoleAssignments(namespace string) RoleAssignmentInterface { + return newRoleAssignments(c, namespace) +} + func (c *OpenstackV1alpha1Client) Routers(namespace string) RouterInterface { return newRouters(c, namespace) } @@ -118,10 +141,22 @@ func (c *OpenstackV1alpha1Client) Services(namespace string) ServiceInterface { return newServices(c, namespace) } +func (c *OpenstackV1alpha1Client) ShareNetworks(namespace string) ShareNetworkInterface { + return newShareNetworks(c, namespace) +} + func (c *OpenstackV1alpha1Client) Subnets(namespace string) SubnetInterface { return newSubnets(c, namespace) } +func (c *OpenstackV1alpha1Client) Trunks(namespace string) TrunkInterface { + return newTrunks(c, namespace) +} + +func (c *OpenstackV1alpha1Client) Users(namespace string) UserInterface { + return newUsers(c, namespace) +} + func (c *OpenstackV1alpha1Client) Volumes(namespace string) VolumeInterface { return newVolumes(c, namespace) } diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/applicationcredential.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/applicationcredential.go new file mode 100644 index 000000000..f3f3411c5 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/applicationcredential.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// ApplicationCredentialsGetter has a method to return a ApplicationCredentialInterface. +// A group's client should implement this interface. +type ApplicationCredentialsGetter interface { + ApplicationCredentials(namespace string) ApplicationCredentialInterface +} + +// ApplicationCredentialInterface has methods to work with ApplicationCredential resources. +type ApplicationCredentialInterface interface { + Create(ctx context.Context, applicationCredential *apiv1alpha1.ApplicationCredential, opts v1.CreateOptions) (*apiv1alpha1.ApplicationCredential, error) + Update(ctx context.Context, applicationCredential *apiv1alpha1.ApplicationCredential, opts v1.UpdateOptions) (*apiv1alpha1.ApplicationCredential, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, applicationCredential *apiv1alpha1.ApplicationCredential, opts v1.UpdateOptions) (*apiv1alpha1.ApplicationCredential, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.ApplicationCredential, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.ApplicationCredentialList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.ApplicationCredential, err error) + Apply(ctx context.Context, applicationCredential *applyconfigurationapiv1alpha1.ApplicationCredentialApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.ApplicationCredential, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, applicationCredential *applyconfigurationapiv1alpha1.ApplicationCredentialApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.ApplicationCredential, err error) + ApplicationCredentialExpansion +} + +// applicationCredentials implements ApplicationCredentialInterface +type applicationCredentials struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.ApplicationCredential, *apiv1alpha1.ApplicationCredentialList, *applyconfigurationapiv1alpha1.ApplicationCredentialApplyConfiguration] +} + +// newApplicationCredentials returns a ApplicationCredentials +func newApplicationCredentials(c *OpenstackV1alpha1Client, namespace string) *applicationCredentials { + return &applicationCredentials{ + gentype.NewClientWithListAndApply[*apiv1alpha1.ApplicationCredential, *apiv1alpha1.ApplicationCredentialList, *applyconfigurationapiv1alpha1.ApplicationCredentialApplyConfiguration]( + "applicationcredentials", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.ApplicationCredential { return &apiv1alpha1.ApplicationCredential{} }, + func() *apiv1alpha1.ApplicationCredentialList { return &apiv1alpha1.ApplicationCredentialList{} }, + ), + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/doc.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/doc.go index b757132de..ab5d0be93 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/doc.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/domain.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/domain.go index f76ed31fe..83ba6d973 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/domain.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/domain.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/endpoint.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/endpoint.go new file mode 100644 index 000000000..4eda9ea43 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/endpoint.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// EndpointsGetter has a method to return a EndpointInterface. +// A group's client should implement this interface. +type EndpointsGetter interface { + Endpoints(namespace string) EndpointInterface +} + +// EndpointInterface has methods to work with Endpoint resources. +type EndpointInterface interface { + Create(ctx context.Context, endpoint *apiv1alpha1.Endpoint, opts v1.CreateOptions) (*apiv1alpha1.Endpoint, error) + Update(ctx context.Context, endpoint *apiv1alpha1.Endpoint, opts v1.UpdateOptions) (*apiv1alpha1.Endpoint, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, endpoint *apiv1alpha1.Endpoint, opts v1.UpdateOptions) (*apiv1alpha1.Endpoint, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.Endpoint, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.EndpointList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.Endpoint, err error) + Apply(ctx context.Context, endpoint *applyconfigurationapiv1alpha1.EndpointApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.Endpoint, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, endpoint *applyconfigurationapiv1alpha1.EndpointApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.Endpoint, err error) + EndpointExpansion +} + +// endpoints implements EndpointInterface +type endpoints struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.Endpoint, *apiv1alpha1.EndpointList, *applyconfigurationapiv1alpha1.EndpointApplyConfiguration] +} + +// newEndpoints returns a Endpoints +func newEndpoints(c *OpenstackV1alpha1Client, namespace string) *endpoints { + return &endpoints{ + gentype.NewClientWithListAndApply[*apiv1alpha1.Endpoint, *apiv1alpha1.EndpointList, *applyconfigurationapiv1alpha1.EndpointApplyConfiguration]( + "endpoints", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.Endpoint { return &apiv1alpha1.Endpoint{} }, + func() *apiv1alpha1.EndpointList { return &apiv1alpha1.EndpointList{} }, + ), + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/doc.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/doc.go index 1b3dfc5a5..d409d454c 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/doc.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_addressscope.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_addressscope.go new file mode 100644 index 000000000..549024d55 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_addressscope.go @@ -0,0 +1,53 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeAddressScopes implements AddressScopeInterface +type fakeAddressScopes struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.AddressScope, *v1alpha1.AddressScopeList, *apiv1alpha1.AddressScopeApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeAddressScopes(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.AddressScopeInterface { + return &fakeAddressScopes{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.AddressScope, *v1alpha1.AddressScopeList, *apiv1alpha1.AddressScopeApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("addressscopes"), + v1alpha1.SchemeGroupVersion.WithKind("AddressScope"), + func() *v1alpha1.AddressScope { return &v1alpha1.AddressScope{} }, + func() *v1alpha1.AddressScopeList { return &v1alpha1.AddressScopeList{} }, + func(dst, src *v1alpha1.AddressScopeList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.AddressScopeList) []*v1alpha1.AddressScope { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha1.AddressScopeList, items []*v1alpha1.AddressScope) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go index 44feeb45c..5015aed35 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,10 +28,22 @@ type FakeOpenstackV1alpha1 struct { *testing.Fake } +func (c *FakeOpenstackV1alpha1) AddressScopes(namespace string) v1alpha1.AddressScopeInterface { + return newFakeAddressScopes(c, namespace) +} + +func (c *FakeOpenstackV1alpha1) ApplicationCredentials(namespace string) v1alpha1.ApplicationCredentialInterface { + return newFakeApplicationCredentials(c, namespace) +} + func (c *FakeOpenstackV1alpha1) Domains(namespace string) v1alpha1.DomainInterface { return newFakeDomains(c, namespace) } +func (c *FakeOpenstackV1alpha1) Endpoints(namespace string) v1alpha1.EndpointInterface { + return newFakeEndpoints(c, namespace) +} + func (c *FakeOpenstackV1alpha1) Flavors(namespace string) v1alpha1.FlavorInterface { return newFakeFlavors(c, namespace) } @@ -68,6 +80,10 @@ func (c *FakeOpenstackV1alpha1) Roles(namespace string) v1alpha1.RoleInterface { return newFakeRoles(c, namespace) } +func (c *FakeOpenstackV1alpha1) RoleAssignments(namespace string) v1alpha1.RoleAssignmentInterface { + return newFakeRoleAssignments(c, namespace) +} + func (c *FakeOpenstackV1alpha1) Routers(namespace string) v1alpha1.RouterInterface { return newFakeRouters(c, namespace) } @@ -92,10 +108,22 @@ func (c *FakeOpenstackV1alpha1) Services(namespace string) v1alpha1.ServiceInter return newFakeServices(c, namespace) } +func (c *FakeOpenstackV1alpha1) ShareNetworks(namespace string) v1alpha1.ShareNetworkInterface { + return newFakeShareNetworks(c, namespace) +} + func (c *FakeOpenstackV1alpha1) Subnets(namespace string) v1alpha1.SubnetInterface { return newFakeSubnets(c, namespace) } +func (c *FakeOpenstackV1alpha1) Trunks(namespace string) v1alpha1.TrunkInterface { + return newFakeTrunks(c, namespace) +} + +func (c *FakeOpenstackV1alpha1) Users(namespace string) v1alpha1.UserInterface { + return newFakeUsers(c, namespace) +} + func (c *FakeOpenstackV1alpha1) Volumes(namespace string) v1alpha1.VolumeInterface { return newFakeVolumes(c, namespace) } diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_applicationcredential.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_applicationcredential.go new file mode 100644 index 000000000..c093e7c28 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_applicationcredential.go @@ -0,0 +1,53 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeApplicationCredentials implements ApplicationCredentialInterface +type fakeApplicationCredentials struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.ApplicationCredential, *v1alpha1.ApplicationCredentialList, *apiv1alpha1.ApplicationCredentialApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeApplicationCredentials(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.ApplicationCredentialInterface { + return &fakeApplicationCredentials{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.ApplicationCredential, *v1alpha1.ApplicationCredentialList, *apiv1alpha1.ApplicationCredentialApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("applicationcredentials"), + v1alpha1.SchemeGroupVersion.WithKind("ApplicationCredential"), + func() *v1alpha1.ApplicationCredential { return &v1alpha1.ApplicationCredential{} }, + func() *v1alpha1.ApplicationCredentialList { return &v1alpha1.ApplicationCredentialList{} }, + func(dst, src *v1alpha1.ApplicationCredentialList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.ApplicationCredentialList) []*v1alpha1.ApplicationCredential { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha1.ApplicationCredentialList, items []*v1alpha1.ApplicationCredential) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_domain.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_domain.go index ef082eb77..ea78b8a40 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_domain.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_domain.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_endpoint.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_endpoint.go new file mode 100644 index 000000000..ab36dca23 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_endpoint.go @@ -0,0 +1,51 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeEndpoints implements EndpointInterface +type fakeEndpoints struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.Endpoint, *v1alpha1.EndpointList, *apiv1alpha1.EndpointApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeEndpoints(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.EndpointInterface { + return &fakeEndpoints{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.Endpoint, *v1alpha1.EndpointList, *apiv1alpha1.EndpointApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("endpoints"), + v1alpha1.SchemeGroupVersion.WithKind("Endpoint"), + func() *v1alpha1.Endpoint { return &v1alpha1.Endpoint{} }, + func() *v1alpha1.EndpointList { return &v1alpha1.EndpointList{} }, + func(dst, src *v1alpha1.EndpointList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.EndpointList) []*v1alpha1.Endpoint { return gentype.ToPointerSlice(list.Items) }, + func(list *v1alpha1.EndpointList, items []*v1alpha1.Endpoint) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_flavor.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_flavor.go index 1686abb94..bf4efd93d 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_flavor.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_flavor.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_floatingip.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_floatingip.go index e720499d5..136c49056 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_floatingip.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_floatingip.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_group.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_group.go index c3a168e1c..2ef581ba1 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_group.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_group.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_image.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_image.go index 6efdd68ea..bc5bbc879 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_image.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_image.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_keypair.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_keypair.go index cbbf5a3a2..37553ac03 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_keypair.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_keypair.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_network.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_network.go index 52d96bb68..f68d65923 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_network.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_network.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_port.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_port.go index 3f20c5d01..540a5ba2c 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_port.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_port.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_project.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_project.go index c1f1f6046..c75981692 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_project.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_project.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_role.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_role.go index e7701df25..3dc54b77d 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_role.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_role.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_roleassignment.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_roleassignment.go new file mode 100644 index 000000000..05bbae41c --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_roleassignment.go @@ -0,0 +1,53 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeRoleAssignments implements RoleAssignmentInterface +type fakeRoleAssignments struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.RoleAssignment, *v1alpha1.RoleAssignmentList, *apiv1alpha1.RoleAssignmentApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeRoleAssignments(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.RoleAssignmentInterface { + return &fakeRoleAssignments{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.RoleAssignment, *v1alpha1.RoleAssignmentList, *apiv1alpha1.RoleAssignmentApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("roleassignments"), + v1alpha1.SchemeGroupVersion.WithKind("RoleAssignment"), + func() *v1alpha1.RoleAssignment { return &v1alpha1.RoleAssignment{} }, + func() *v1alpha1.RoleAssignmentList { return &v1alpha1.RoleAssignmentList{} }, + func(dst, src *v1alpha1.RoleAssignmentList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.RoleAssignmentList) []*v1alpha1.RoleAssignment { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha1.RoleAssignmentList, items []*v1alpha1.RoleAssignment) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_router.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_router.go index 831c9220e..dec48bdd2 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_router.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_router.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_routerinterface.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_routerinterface.go index 34d76d5cd..b519e73e8 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_routerinterface.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_routerinterface.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_securitygroup.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_securitygroup.go index 2ef4b1ba6..865fb786c 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_securitygroup.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_securitygroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_server.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_server.go index 9ae492970..a8e37ad42 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_server.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_server.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_servergroup.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_servergroup.go index 61816c71a..3c1cbf2fb 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_servergroup.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_servergroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_service.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_service.go index 0c175dad5..17971c02b 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_service.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_service.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_sharenetwork.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_sharenetwork.go new file mode 100644 index 000000000..2e1081d9f --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_sharenetwork.go @@ -0,0 +1,53 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeShareNetworks implements ShareNetworkInterface +type fakeShareNetworks struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.ShareNetwork, *v1alpha1.ShareNetworkList, *apiv1alpha1.ShareNetworkApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeShareNetworks(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.ShareNetworkInterface { + return &fakeShareNetworks{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.ShareNetwork, *v1alpha1.ShareNetworkList, *apiv1alpha1.ShareNetworkApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("sharenetworks"), + v1alpha1.SchemeGroupVersion.WithKind("ShareNetwork"), + func() *v1alpha1.ShareNetwork { return &v1alpha1.ShareNetwork{} }, + func() *v1alpha1.ShareNetworkList { return &v1alpha1.ShareNetworkList{} }, + func(dst, src *v1alpha1.ShareNetworkList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.ShareNetworkList) []*v1alpha1.ShareNetwork { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha1.ShareNetworkList, items []*v1alpha1.ShareNetwork) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_subnet.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_subnet.go index 540939764..9dd38a30f 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_subnet.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_subnet.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_trunk.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_trunk.go new file mode 100644 index 000000000..bc58f0e4d --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_trunk.go @@ -0,0 +1,49 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeTrunks implements TrunkInterface +type fakeTrunks struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.Trunk, *v1alpha1.TrunkList, *apiv1alpha1.TrunkApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeTrunks(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.TrunkInterface { + return &fakeTrunks{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.Trunk, *v1alpha1.TrunkList, *apiv1alpha1.TrunkApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("trunks"), + v1alpha1.SchemeGroupVersion.WithKind("Trunk"), + func() *v1alpha1.Trunk { return &v1alpha1.Trunk{} }, + func() *v1alpha1.TrunkList { return &v1alpha1.TrunkList{} }, + func(dst, src *v1alpha1.TrunkList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.TrunkList) []*v1alpha1.Trunk { return gentype.ToPointerSlice(list.Items) }, + func(list *v1alpha1.TrunkList, items []*v1alpha1.Trunk) { list.Items = gentype.FromPointerSlice(items) }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_user.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_user.go new file mode 100644 index 000000000..c3ac6b668 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_user.go @@ -0,0 +1,49 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeUsers implements UserInterface +type fakeUsers struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.User, *v1alpha1.UserList, *apiv1alpha1.UserApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeUsers(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.UserInterface { + return &fakeUsers{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.User, *v1alpha1.UserList, *apiv1alpha1.UserApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("users"), + v1alpha1.SchemeGroupVersion.WithKind("User"), + func() *v1alpha1.User { return &v1alpha1.User{} }, + func() *v1alpha1.UserList { return &v1alpha1.UserList{} }, + func(dst, src *v1alpha1.UserList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.UserList) []*v1alpha1.User { return gentype.ToPointerSlice(list.Items) }, + func(list *v1alpha1.UserList, items []*v1alpha1.User) { list.Items = gentype.FromPointerSlice(items) }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volume.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volume.go index c1097298c..fef4e1e78 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volume.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volume.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volumetype.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volumetype.go index 7797551bd..126aebd95 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volumetype.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_volumetype.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/flavor.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/flavor.go index d2bcfddad..7f59e0ef1 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/flavor.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/flavor.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/floatingip.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/floatingip.go index defa84705..00a9802a4 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/floatingip.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/floatingip.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go index 56550a99f..7c5d67d45 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,8 +18,14 @@ limitations under the License. package v1alpha1 +type AddressScopeExpansion interface{} + +type ApplicationCredentialExpansion interface{} + type DomainExpansion interface{} +type EndpointExpansion interface{} + type FlavorExpansion interface{} type FloatingIPExpansion interface{} @@ -38,6 +44,8 @@ type ProjectExpansion interface{} type RoleExpansion interface{} +type RoleAssignmentExpansion interface{} + type RouterExpansion interface{} type RouterInterfaceExpansion interface{} @@ -50,8 +58,14 @@ type ServerGroupExpansion interface{} type ServiceExpansion interface{} +type ShareNetworkExpansion interface{} + type SubnetExpansion interface{} +type TrunkExpansion interface{} + +type UserExpansion interface{} + type VolumeExpansion interface{} type VolumeTypeExpansion interface{} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/group.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/group.go index 5dc034c44..a8e168094 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/group.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/group.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/image.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/image.go index d15056837..bb719a623 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/image.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/image.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/keypair.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/keypair.go index 71d9d50b6..f2d1f177e 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/keypair.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/keypair.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/network.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/network.go index bd0756eb5..2422c0b25 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/network.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/network.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/port.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/port.go index 33fd81223..e59bc653b 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/port.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/port.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/project.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/project.go index 5dfd39fd6..e777bff87 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/project.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/project.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/role.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/role.go index 779708067..5ac1433f6 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/role.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/role.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/roleassignment.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/roleassignment.go new file mode 100644 index 000000000..37d5f5a96 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/roleassignment.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// RoleAssignmentsGetter has a method to return a RoleAssignmentInterface. +// A group's client should implement this interface. +type RoleAssignmentsGetter interface { + RoleAssignments(namespace string) RoleAssignmentInterface +} + +// RoleAssignmentInterface has methods to work with RoleAssignment resources. +type RoleAssignmentInterface interface { + Create(ctx context.Context, roleAssignment *apiv1alpha1.RoleAssignment, opts v1.CreateOptions) (*apiv1alpha1.RoleAssignment, error) + Update(ctx context.Context, roleAssignment *apiv1alpha1.RoleAssignment, opts v1.UpdateOptions) (*apiv1alpha1.RoleAssignment, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, roleAssignment *apiv1alpha1.RoleAssignment, opts v1.UpdateOptions) (*apiv1alpha1.RoleAssignment, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.RoleAssignment, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.RoleAssignmentList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.RoleAssignment, err error) + Apply(ctx context.Context, roleAssignment *applyconfigurationapiv1alpha1.RoleAssignmentApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.RoleAssignment, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, roleAssignment *applyconfigurationapiv1alpha1.RoleAssignmentApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.RoleAssignment, err error) + RoleAssignmentExpansion +} + +// roleAssignments implements RoleAssignmentInterface +type roleAssignments struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.RoleAssignment, *apiv1alpha1.RoleAssignmentList, *applyconfigurationapiv1alpha1.RoleAssignmentApplyConfiguration] +} + +// newRoleAssignments returns a RoleAssignments +func newRoleAssignments(c *OpenstackV1alpha1Client, namespace string) *roleAssignments { + return &roleAssignments{ + gentype.NewClientWithListAndApply[*apiv1alpha1.RoleAssignment, *apiv1alpha1.RoleAssignmentList, *applyconfigurationapiv1alpha1.RoleAssignmentApplyConfiguration]( + "roleassignments", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.RoleAssignment { return &apiv1alpha1.RoleAssignment{} }, + func() *apiv1alpha1.RoleAssignmentList { return &apiv1alpha1.RoleAssignmentList{} }, + ), + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/router.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/router.go index 0e092644d..5da2176b0 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/router.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/router.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/routerinterface.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/routerinterface.go index 195f91f02..3d6e86c32 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/routerinterface.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/routerinterface.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/securitygroup.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/securitygroup.go index c71c2affe..d996525f2 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/securitygroup.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/securitygroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/server.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/server.go index 0fba20892..77e068970 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/server.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/server.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/servergroup.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/servergroup.go index 4966a6301..71d968283 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/servergroup.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/servergroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/service.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/service.go index 1fc5509ea..ed1f4ddca 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/service.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/service.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/sharenetwork.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/sharenetwork.go new file mode 100644 index 000000000..1c64adfc7 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/sharenetwork.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// ShareNetworksGetter has a method to return a ShareNetworkInterface. +// A group's client should implement this interface. +type ShareNetworksGetter interface { + ShareNetworks(namespace string) ShareNetworkInterface +} + +// ShareNetworkInterface has methods to work with ShareNetwork resources. +type ShareNetworkInterface interface { + Create(ctx context.Context, shareNetwork *apiv1alpha1.ShareNetwork, opts v1.CreateOptions) (*apiv1alpha1.ShareNetwork, error) + Update(ctx context.Context, shareNetwork *apiv1alpha1.ShareNetwork, opts v1.UpdateOptions) (*apiv1alpha1.ShareNetwork, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, shareNetwork *apiv1alpha1.ShareNetwork, opts v1.UpdateOptions) (*apiv1alpha1.ShareNetwork, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.ShareNetwork, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.ShareNetworkList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.ShareNetwork, err error) + Apply(ctx context.Context, shareNetwork *applyconfigurationapiv1alpha1.ShareNetworkApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.ShareNetwork, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, shareNetwork *applyconfigurationapiv1alpha1.ShareNetworkApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.ShareNetwork, err error) + ShareNetworkExpansion +} + +// shareNetworks implements ShareNetworkInterface +type shareNetworks struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.ShareNetwork, *apiv1alpha1.ShareNetworkList, *applyconfigurationapiv1alpha1.ShareNetworkApplyConfiguration] +} + +// newShareNetworks returns a ShareNetworks +func newShareNetworks(c *OpenstackV1alpha1Client, namespace string) *shareNetworks { + return &shareNetworks{ + gentype.NewClientWithListAndApply[*apiv1alpha1.ShareNetwork, *apiv1alpha1.ShareNetworkList, *applyconfigurationapiv1alpha1.ShareNetworkApplyConfiguration]( + "sharenetworks", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.ShareNetwork { return &apiv1alpha1.ShareNetwork{} }, + func() *apiv1alpha1.ShareNetworkList { return &apiv1alpha1.ShareNetworkList{} }, + ), + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/subnet.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/subnet.go index 10bebdfc7..8ef009c1f 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/subnet.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/subnet.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/trunk.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/trunk.go new file mode 100644 index 000000000..0a2dd9152 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/trunk.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// TrunksGetter has a method to return a TrunkInterface. +// A group's client should implement this interface. +type TrunksGetter interface { + Trunks(namespace string) TrunkInterface +} + +// TrunkInterface has methods to work with Trunk resources. +type TrunkInterface interface { + Create(ctx context.Context, trunk *apiv1alpha1.Trunk, opts v1.CreateOptions) (*apiv1alpha1.Trunk, error) + Update(ctx context.Context, trunk *apiv1alpha1.Trunk, opts v1.UpdateOptions) (*apiv1alpha1.Trunk, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, trunk *apiv1alpha1.Trunk, opts v1.UpdateOptions) (*apiv1alpha1.Trunk, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.Trunk, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.TrunkList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.Trunk, err error) + Apply(ctx context.Context, trunk *applyconfigurationapiv1alpha1.TrunkApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.Trunk, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, trunk *applyconfigurationapiv1alpha1.TrunkApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.Trunk, err error) + TrunkExpansion +} + +// trunks implements TrunkInterface +type trunks struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.Trunk, *apiv1alpha1.TrunkList, *applyconfigurationapiv1alpha1.TrunkApplyConfiguration] +} + +// newTrunks returns a Trunks +func newTrunks(c *OpenstackV1alpha1Client, namespace string) *trunks { + return &trunks{ + gentype.NewClientWithListAndApply[*apiv1alpha1.Trunk, *apiv1alpha1.TrunkList, *applyconfigurationapiv1alpha1.TrunkApplyConfiguration]( + "trunks", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.Trunk { return &apiv1alpha1.Trunk{} }, + func() *apiv1alpha1.TrunkList { return &apiv1alpha1.TrunkList{} }, + ), + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/user.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/user.go new file mode 100644 index 000000000..d2f6659a7 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/user.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// UsersGetter has a method to return a UserInterface. +// A group's client should implement this interface. +type UsersGetter interface { + Users(namespace string) UserInterface +} + +// UserInterface has methods to work with User resources. +type UserInterface interface { + Create(ctx context.Context, user *apiv1alpha1.User, opts v1.CreateOptions) (*apiv1alpha1.User, error) + Update(ctx context.Context, user *apiv1alpha1.User, opts v1.UpdateOptions) (*apiv1alpha1.User, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, user *apiv1alpha1.User, opts v1.UpdateOptions) (*apiv1alpha1.User, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.User, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.UserList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.User, err error) + Apply(ctx context.Context, user *applyconfigurationapiv1alpha1.UserApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.User, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, user *applyconfigurationapiv1alpha1.UserApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.User, err error) + UserExpansion +} + +// users implements UserInterface +type users struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.User, *apiv1alpha1.UserList, *applyconfigurationapiv1alpha1.UserApplyConfiguration] +} + +// newUsers returns a Users +func newUsers(c *OpenstackV1alpha1Client, namespace string) *users { + return &users{ + gentype.NewClientWithListAndApply[*apiv1alpha1.User, *apiv1alpha1.UserList, *applyconfigurationapiv1alpha1.UserApplyConfiguration]( + "users", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.User { return &apiv1alpha1.User{} }, + func() *apiv1alpha1.UserList { return &apiv1alpha1.UserList{} }, + ), + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/volume.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/volume.go index 966563255..7c5147c1f 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/volume.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/volume.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/volumetype.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/volumetype.go index 352e3c31e..8aa0602c7 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/volumetype.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/volumetype.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/interface.go b/pkg/clients/informers/externalversions/api/interface.go index 796462031..ca024a2e7 100644 --- a/pkg/clients/informers/externalversions/api/interface.go +++ b/pkg/clients/informers/externalversions/api/interface.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/addressscope.go b/pkg/clients/informers/externalversions/api/v1alpha1/addressscope.go new file mode 100644 index 000000000..39f360e11 --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/addressscope.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// AddressScopeInformer provides access to a shared informer and lister for +// AddressScopes. +type AddressScopeInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.AddressScopeLister +} + +type addressScopeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewAddressScopeInformer constructs a new informer for AddressScope type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewAddressScopeInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredAddressScopeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredAddressScopeInformer constructs a new informer for AddressScope type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredAddressScopeInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().AddressScopes(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().AddressScopes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().AddressScopes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().AddressScopes(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.AddressScope{}, + resyncPeriod, + indexers, + ) +} + +func (f *addressScopeInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredAddressScopeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *addressScopeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.AddressScope{}, f.defaultInformer) +} + +func (f *addressScopeInformer) Lister() apiv1alpha1.AddressScopeLister { + return apiv1alpha1.NewAddressScopeLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/applicationcredential.go b/pkg/clients/informers/externalversions/api/v1alpha1/applicationcredential.go new file mode 100644 index 000000000..a728706a7 --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/applicationcredential.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ApplicationCredentialInformer provides access to a shared informer and lister for +// ApplicationCredentials. +type ApplicationCredentialInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.ApplicationCredentialLister +} + +type applicationCredentialInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewApplicationCredentialInformer constructs a new informer for ApplicationCredential type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewApplicationCredentialInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredApplicationCredentialInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredApplicationCredentialInformer constructs a new informer for ApplicationCredential type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredApplicationCredentialInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ApplicationCredentials(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ApplicationCredentials(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ApplicationCredentials(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ApplicationCredentials(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.ApplicationCredential{}, + resyncPeriod, + indexers, + ) +} + +func (f *applicationCredentialInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredApplicationCredentialInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *applicationCredentialInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.ApplicationCredential{}, f.defaultInformer) +} + +func (f *applicationCredentialInformer) Lister() apiv1alpha1.ApplicationCredentialLister { + return apiv1alpha1.NewApplicationCredentialLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/domain.go b/pkg/clients/informers/externalversions/api/v1alpha1/domain.go index 4c5fba2de..2e0a8879a 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/domain.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/domain.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/endpoint.go b/pkg/clients/informers/externalversions/api/v1alpha1/endpoint.go new file mode 100644 index 000000000..7deada74f --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/endpoint.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// EndpointInformer provides access to a shared informer and lister for +// Endpoints. +type EndpointInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.EndpointLister +} + +type endpointInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewEndpointInformer constructs a new informer for Endpoint type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewEndpointInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredEndpointInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredEndpointInformer constructs a new informer for Endpoint type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredEndpointInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Endpoints(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Endpoints(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Endpoints(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Endpoints(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.Endpoint{}, + resyncPeriod, + indexers, + ) +} + +func (f *endpointInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredEndpointInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *endpointInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.Endpoint{}, f.defaultInformer) +} + +func (f *endpointInformer) Lister() apiv1alpha1.EndpointLister { + return apiv1alpha1.NewEndpointLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/flavor.go b/pkg/clients/informers/externalversions/api/v1alpha1/flavor.go index 3a941fc22..4f371b017 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/flavor.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/flavor.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/floatingip.go b/pkg/clients/informers/externalversions/api/v1alpha1/floatingip.go index 65cf18f1c..099d674b5 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/floatingip.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/floatingip.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/group.go b/pkg/clients/informers/externalversions/api/v1alpha1/group.go index c240e2021..eefe73c64 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/group.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/group.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/image.go b/pkg/clients/informers/externalversions/api/v1alpha1/image.go index c0a97354c..707dcfacd 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/image.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/image.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/interface.go b/pkg/clients/informers/externalversions/api/v1alpha1/interface.go index 1b4497815..69d2bdeaf 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/interface.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/interface.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,8 +24,14 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // AddressScopes returns a AddressScopeInformer. + AddressScopes() AddressScopeInformer + // ApplicationCredentials returns a ApplicationCredentialInformer. + ApplicationCredentials() ApplicationCredentialInformer // Domains returns a DomainInformer. Domains() DomainInformer + // Endpoints returns a EndpointInformer. + Endpoints() EndpointInformer // Flavors returns a FlavorInformer. Flavors() FlavorInformer // FloatingIPs returns a FloatingIPInformer. @@ -44,6 +50,8 @@ type Interface interface { Projects() ProjectInformer // Roles returns a RoleInformer. Roles() RoleInformer + // RoleAssignments returns a RoleAssignmentInformer. + RoleAssignments() RoleAssignmentInformer // Routers returns a RouterInformer. Routers() RouterInformer // RouterInterfaces returns a RouterInterfaceInformer. @@ -56,8 +64,14 @@ type Interface interface { ServerGroups() ServerGroupInformer // Services returns a ServiceInformer. Services() ServiceInformer + // ShareNetworks returns a ShareNetworkInformer. + ShareNetworks() ShareNetworkInformer // Subnets returns a SubnetInformer. Subnets() SubnetInformer + // Trunks returns a TrunkInformer. + Trunks() TrunkInformer + // Users returns a UserInformer. + Users() UserInformer // Volumes returns a VolumeInformer. Volumes() VolumeInformer // VolumeTypes returns a VolumeTypeInformer. @@ -75,11 +89,26 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// AddressScopes returns a AddressScopeInformer. +func (v *version) AddressScopes() AddressScopeInformer { + return &addressScopeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// ApplicationCredentials returns a ApplicationCredentialInformer. +func (v *version) ApplicationCredentials() ApplicationCredentialInformer { + return &applicationCredentialInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Domains returns a DomainInformer. func (v *version) Domains() DomainInformer { return &domainInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// Endpoints returns a EndpointInformer. +func (v *version) Endpoints() EndpointInformer { + return &endpointInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Flavors returns a FlavorInformer. func (v *version) Flavors() FlavorInformer { return &flavorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} @@ -125,6 +154,11 @@ func (v *version) Roles() RoleInformer { return &roleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// RoleAssignments returns a RoleAssignmentInformer. +func (v *version) RoleAssignments() RoleAssignmentInformer { + return &roleAssignmentInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Routers returns a RouterInformer. func (v *version) Routers() RouterInformer { return &routerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} @@ -155,11 +189,26 @@ func (v *version) Services() ServiceInformer { return &serviceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// ShareNetworks returns a ShareNetworkInformer. +func (v *version) ShareNetworks() ShareNetworkInformer { + return &shareNetworkInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Subnets returns a SubnetInformer. func (v *version) Subnets() SubnetInformer { return &subnetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// Trunks returns a TrunkInformer. +func (v *version) Trunks() TrunkInformer { + return &trunkInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Users returns a UserInformer. +func (v *version) Users() UserInformer { + return &userInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Volumes returns a VolumeInformer. func (v *version) Volumes() VolumeInformer { return &volumeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/keypair.go b/pkg/clients/informers/externalversions/api/v1alpha1/keypair.go index f0c1e2b57..33ef79fd4 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/keypair.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/keypair.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/network.go b/pkg/clients/informers/externalversions/api/v1alpha1/network.go index 24e300230..84e12259c 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/network.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/network.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/port.go b/pkg/clients/informers/externalversions/api/v1alpha1/port.go index 8eeaa5406..7e037c84d 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/port.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/port.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/project.go b/pkg/clients/informers/externalversions/api/v1alpha1/project.go index 345ac1c19..0025d8e21 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/project.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/project.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/role.go b/pkg/clients/informers/externalversions/api/v1alpha1/role.go index cfdb7de7a..7975f8f7e 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/role.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/role.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/roleassignment.go b/pkg/clients/informers/externalversions/api/v1alpha1/roleassignment.go new file mode 100644 index 000000000..d34221cf4 --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/roleassignment.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// RoleAssignmentInformer provides access to a shared informer and lister for +// RoleAssignments. +type RoleAssignmentInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.RoleAssignmentLister +} + +type roleAssignmentInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewRoleAssignmentInformer constructs a new informer for RoleAssignment type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewRoleAssignmentInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRoleAssignmentInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredRoleAssignmentInformer constructs a new informer for RoleAssignment type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredRoleAssignmentInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RoleAssignments(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RoleAssignments(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RoleAssignments(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RoleAssignments(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.RoleAssignment{}, + resyncPeriod, + indexers, + ) +} + +func (f *roleAssignmentInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRoleAssignmentInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *roleAssignmentInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.RoleAssignment{}, f.defaultInformer) +} + +func (f *roleAssignmentInformer) Lister() apiv1alpha1.RoleAssignmentLister { + return apiv1alpha1.NewRoleAssignmentLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/router.go b/pkg/clients/informers/externalversions/api/v1alpha1/router.go index 8e5d3d4a2..fc472b5bd 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/router.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/router.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/routerinterface.go b/pkg/clients/informers/externalversions/api/v1alpha1/routerinterface.go index 1f94db3ab..b937e51f7 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/routerinterface.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/routerinterface.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/securitygroup.go b/pkg/clients/informers/externalversions/api/v1alpha1/securitygroup.go index 7680e921a..385356ccc 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/securitygroup.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/securitygroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/server.go b/pkg/clients/informers/externalversions/api/v1alpha1/server.go index 416e0ee84..130029213 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/server.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/server.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/servergroup.go b/pkg/clients/informers/externalversions/api/v1alpha1/servergroup.go index 70c6c1e33..3a3fd71c3 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/servergroup.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/servergroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/service.go b/pkg/clients/informers/externalversions/api/v1alpha1/service.go index dd9f14d78..43ca18e0a 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/service.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/service.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/sharenetwork.go b/pkg/clients/informers/externalversions/api/v1alpha1/sharenetwork.go new file mode 100644 index 000000000..1b9c5c3d2 --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/sharenetwork.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ShareNetworkInformer provides access to a shared informer and lister for +// ShareNetworks. +type ShareNetworkInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.ShareNetworkLister +} + +type shareNetworkInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewShareNetworkInformer constructs a new informer for ShareNetwork type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewShareNetworkInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredShareNetworkInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredShareNetworkInformer constructs a new informer for ShareNetwork type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredShareNetworkInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ShareNetworks(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ShareNetworks(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ShareNetworks(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().ShareNetworks(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.ShareNetwork{}, + resyncPeriod, + indexers, + ) +} + +func (f *shareNetworkInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredShareNetworkInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *shareNetworkInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.ShareNetwork{}, f.defaultInformer) +} + +func (f *shareNetworkInformer) Lister() apiv1alpha1.ShareNetworkLister { + return apiv1alpha1.NewShareNetworkLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/subnet.go b/pkg/clients/informers/externalversions/api/v1alpha1/subnet.go index 4bfc120f0..6a902f657 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/subnet.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/subnet.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/trunk.go b/pkg/clients/informers/externalversions/api/v1alpha1/trunk.go new file mode 100644 index 000000000..0f3eea4fd --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/trunk.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// TrunkInformer provides access to a shared informer and lister for +// Trunks. +type TrunkInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.TrunkLister +} + +type trunkInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTrunkInformer constructs a new informer for Trunk type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTrunkInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTrunkInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTrunkInformer constructs a new informer for Trunk type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTrunkInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Trunks(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Trunks(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Trunks(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Trunks(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.Trunk{}, + resyncPeriod, + indexers, + ) +} + +func (f *trunkInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTrunkInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *trunkInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.Trunk{}, f.defaultInformer) +} + +func (f *trunkInformer) Lister() apiv1alpha1.TrunkLister { + return apiv1alpha1.NewTrunkLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/user.go b/pkg/clients/informers/externalversions/api/v1alpha1/user.go new file mode 100644 index 000000000..3cdb83f5f --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/user.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// UserInformer provides access to a shared informer and lister for +// Users. +type UserInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.UserLister +} + +type userInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewUserInformer constructs a new informer for User type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewUserInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredUserInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredUserInformer constructs a new informer for User type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredUserInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Users(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Users(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Users(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().Users(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.User{}, + resyncPeriod, + indexers, + ) +} + +func (f *userInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredUserInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *userInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.User{}, f.defaultInformer) +} + +func (f *userInformer) Lister() apiv1alpha1.UserLister { + return apiv1alpha1.NewUserLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/volume.go b/pkg/clients/informers/externalversions/api/v1alpha1/volume.go index fb175347a..c42cc57a0 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/volume.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/volume.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/volumetype.go b/pkg/clients/informers/externalversions/api/v1alpha1/volumetype.go index be022c62a..34b6336eb 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/volumetype.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/volumetype.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/factory.go b/pkg/clients/informers/externalversions/factory.go index 3f0620df3..2260c31fb 100644 --- a/pkg/clients/informers/externalversions/factory.go +++ b/pkg/clients/informers/externalversions/factory.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/informers/externalversions/generic.go b/pkg/clients/informers/externalversions/generic.go index 30911d11f..f58420886 100644 --- a/pkg/clients/informers/externalversions/generic.go +++ b/pkg/clients/informers/externalversions/generic.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -53,8 +53,14 @@ func (f *genericInformer) Lister() cache.GenericLister { func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { // Group=openstack.k-orc.cloud, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("addressscopes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().AddressScopes().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("applicationcredentials"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().ApplicationCredentials().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("domains"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Domains().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("endpoints"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Endpoints().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("flavors"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Flavors().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("floatingips"): @@ -73,6 +79,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Projects().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("roles"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Roles().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("roleassignments"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().RoleAssignments().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("routers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Routers().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("routerinterfaces"): @@ -85,8 +93,14 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().ServerGroups().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("services"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Services().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("sharenetworks"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().ShareNetworks().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("subnets"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Subnets().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("trunks"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Trunks().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("users"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Users().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("volumes"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Volumes().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("volumetypes"): diff --git a/pkg/clients/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/clients/informers/externalversions/internalinterfaces/factory_interfaces.go index 1ff80aa05..38e582cf3 100644 --- a/pkg/clients/informers/externalversions/internalinterfaces/factory_interfaces.go +++ b/pkg/clients/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/addressscope.go b/pkg/clients/listers/api/v1alpha1/addressscope.go new file mode 100644 index 000000000..b2a8b7929 --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/addressscope.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// AddressScopeLister helps list AddressScopes. +// All objects returned here must be treated as read-only. +type AddressScopeLister interface { + // List lists all AddressScopes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.AddressScope, err error) + // AddressScopes returns an object that can list and get AddressScopes. + AddressScopes(namespace string) AddressScopeNamespaceLister + AddressScopeListerExpansion +} + +// addressScopeLister implements the AddressScopeLister interface. +type addressScopeLister struct { + listers.ResourceIndexer[*apiv1alpha1.AddressScope] +} + +// NewAddressScopeLister returns a new AddressScopeLister. +func NewAddressScopeLister(indexer cache.Indexer) AddressScopeLister { + return &addressScopeLister{listers.New[*apiv1alpha1.AddressScope](indexer, apiv1alpha1.Resource("addressscope"))} +} + +// AddressScopes returns an object that can list and get AddressScopes. +func (s *addressScopeLister) AddressScopes(namespace string) AddressScopeNamespaceLister { + return addressScopeNamespaceLister{listers.NewNamespaced[*apiv1alpha1.AddressScope](s.ResourceIndexer, namespace)} +} + +// AddressScopeNamespaceLister helps list and get AddressScopes. +// All objects returned here must be treated as read-only. +type AddressScopeNamespaceLister interface { + // List lists all AddressScopes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.AddressScope, err error) + // Get retrieves the AddressScope from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.AddressScope, error) + AddressScopeNamespaceListerExpansion +} + +// addressScopeNamespaceLister implements the AddressScopeNamespaceLister +// interface. +type addressScopeNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.AddressScope] +} diff --git a/pkg/clients/listers/api/v1alpha1/applicationcredential.go b/pkg/clients/listers/api/v1alpha1/applicationcredential.go new file mode 100644 index 000000000..559f9b947 --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/applicationcredential.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// ApplicationCredentialLister helps list ApplicationCredentials. +// All objects returned here must be treated as read-only. +type ApplicationCredentialLister interface { + // List lists all ApplicationCredentials in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.ApplicationCredential, err error) + // ApplicationCredentials returns an object that can list and get ApplicationCredentials. + ApplicationCredentials(namespace string) ApplicationCredentialNamespaceLister + ApplicationCredentialListerExpansion +} + +// applicationCredentialLister implements the ApplicationCredentialLister interface. +type applicationCredentialLister struct { + listers.ResourceIndexer[*apiv1alpha1.ApplicationCredential] +} + +// NewApplicationCredentialLister returns a new ApplicationCredentialLister. +func NewApplicationCredentialLister(indexer cache.Indexer) ApplicationCredentialLister { + return &applicationCredentialLister{listers.New[*apiv1alpha1.ApplicationCredential](indexer, apiv1alpha1.Resource("applicationcredential"))} +} + +// ApplicationCredentials returns an object that can list and get ApplicationCredentials. +func (s *applicationCredentialLister) ApplicationCredentials(namespace string) ApplicationCredentialNamespaceLister { + return applicationCredentialNamespaceLister{listers.NewNamespaced[*apiv1alpha1.ApplicationCredential](s.ResourceIndexer, namespace)} +} + +// ApplicationCredentialNamespaceLister helps list and get ApplicationCredentials. +// All objects returned here must be treated as read-only. +type ApplicationCredentialNamespaceLister interface { + // List lists all ApplicationCredentials in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.ApplicationCredential, err error) + // Get retrieves the ApplicationCredential from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.ApplicationCredential, error) + ApplicationCredentialNamespaceListerExpansion +} + +// applicationCredentialNamespaceLister implements the ApplicationCredentialNamespaceLister +// interface. +type applicationCredentialNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.ApplicationCredential] +} diff --git a/pkg/clients/listers/api/v1alpha1/domain.go b/pkg/clients/listers/api/v1alpha1/domain.go index 4cae34fba..1e3d17051 100644 --- a/pkg/clients/listers/api/v1alpha1/domain.go +++ b/pkg/clients/listers/api/v1alpha1/domain.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/endpoint.go b/pkg/clients/listers/api/v1alpha1/endpoint.go new file mode 100644 index 000000000..1d7599408 --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/endpoint.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// EndpointLister helps list Endpoints. +// All objects returned here must be treated as read-only. +type EndpointLister interface { + // List lists all Endpoints in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.Endpoint, err error) + // Endpoints returns an object that can list and get Endpoints. + Endpoints(namespace string) EndpointNamespaceLister + EndpointListerExpansion +} + +// endpointLister implements the EndpointLister interface. +type endpointLister struct { + listers.ResourceIndexer[*apiv1alpha1.Endpoint] +} + +// NewEndpointLister returns a new EndpointLister. +func NewEndpointLister(indexer cache.Indexer) EndpointLister { + return &endpointLister{listers.New[*apiv1alpha1.Endpoint](indexer, apiv1alpha1.Resource("endpoint"))} +} + +// Endpoints returns an object that can list and get Endpoints. +func (s *endpointLister) Endpoints(namespace string) EndpointNamespaceLister { + return endpointNamespaceLister{listers.NewNamespaced[*apiv1alpha1.Endpoint](s.ResourceIndexer, namespace)} +} + +// EndpointNamespaceLister helps list and get Endpoints. +// All objects returned here must be treated as read-only. +type EndpointNamespaceLister interface { + // List lists all Endpoints in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.Endpoint, err error) + // Get retrieves the Endpoint from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.Endpoint, error) + EndpointNamespaceListerExpansion +} + +// endpointNamespaceLister implements the EndpointNamespaceLister +// interface. +type endpointNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.Endpoint] +} diff --git a/pkg/clients/listers/api/v1alpha1/expansion_generated.go b/pkg/clients/listers/api/v1alpha1/expansion_generated.go index ba2888731..76fec1603 100644 --- a/pkg/clients/listers/api/v1alpha1/expansion_generated.go +++ b/pkg/clients/listers/api/v1alpha1/expansion_generated.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +18,22 @@ limitations under the License. package v1alpha1 +// AddressScopeListerExpansion allows custom methods to be added to +// AddressScopeLister. +type AddressScopeListerExpansion interface{} + +// AddressScopeNamespaceListerExpansion allows custom methods to be added to +// AddressScopeNamespaceLister. +type AddressScopeNamespaceListerExpansion interface{} + +// ApplicationCredentialListerExpansion allows custom methods to be added to +// ApplicationCredentialLister. +type ApplicationCredentialListerExpansion interface{} + +// ApplicationCredentialNamespaceListerExpansion allows custom methods to be added to +// ApplicationCredentialNamespaceLister. +type ApplicationCredentialNamespaceListerExpansion interface{} + // DomainListerExpansion allows custom methods to be added to // DomainLister. type DomainListerExpansion interface{} @@ -26,6 +42,14 @@ type DomainListerExpansion interface{} // DomainNamespaceLister. type DomainNamespaceListerExpansion interface{} +// EndpointListerExpansion allows custom methods to be added to +// EndpointLister. +type EndpointListerExpansion interface{} + +// EndpointNamespaceListerExpansion allows custom methods to be added to +// EndpointNamespaceLister. +type EndpointNamespaceListerExpansion interface{} + // FlavorListerExpansion allows custom methods to be added to // FlavorLister. type FlavorListerExpansion interface{} @@ -98,6 +122,14 @@ type RoleListerExpansion interface{} // RoleNamespaceLister. type RoleNamespaceListerExpansion interface{} +// RoleAssignmentListerExpansion allows custom methods to be added to +// RoleAssignmentLister. +type RoleAssignmentListerExpansion interface{} + +// RoleAssignmentNamespaceListerExpansion allows custom methods to be added to +// RoleAssignmentNamespaceLister. +type RoleAssignmentNamespaceListerExpansion interface{} + // RouterListerExpansion allows custom methods to be added to // RouterLister. type RouterListerExpansion interface{} @@ -146,6 +178,14 @@ type ServiceListerExpansion interface{} // ServiceNamespaceLister. type ServiceNamespaceListerExpansion interface{} +// ShareNetworkListerExpansion allows custom methods to be added to +// ShareNetworkLister. +type ShareNetworkListerExpansion interface{} + +// ShareNetworkNamespaceListerExpansion allows custom methods to be added to +// ShareNetworkNamespaceLister. +type ShareNetworkNamespaceListerExpansion interface{} + // SubnetListerExpansion allows custom methods to be added to // SubnetLister. type SubnetListerExpansion interface{} @@ -154,6 +194,22 @@ type SubnetListerExpansion interface{} // SubnetNamespaceLister. type SubnetNamespaceListerExpansion interface{} +// TrunkListerExpansion allows custom methods to be added to +// TrunkLister. +type TrunkListerExpansion interface{} + +// TrunkNamespaceListerExpansion allows custom methods to be added to +// TrunkNamespaceLister. +type TrunkNamespaceListerExpansion interface{} + +// UserListerExpansion allows custom methods to be added to +// UserLister. +type UserListerExpansion interface{} + +// UserNamespaceListerExpansion allows custom methods to be added to +// UserNamespaceLister. +type UserNamespaceListerExpansion interface{} + // VolumeListerExpansion allows custom methods to be added to // VolumeLister. type VolumeListerExpansion interface{} diff --git a/pkg/clients/listers/api/v1alpha1/flavor.go b/pkg/clients/listers/api/v1alpha1/flavor.go index 0f8cb4282..820fe098a 100644 --- a/pkg/clients/listers/api/v1alpha1/flavor.go +++ b/pkg/clients/listers/api/v1alpha1/flavor.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/floatingip.go b/pkg/clients/listers/api/v1alpha1/floatingip.go index f41a20321..f7dbc95c5 100644 --- a/pkg/clients/listers/api/v1alpha1/floatingip.go +++ b/pkg/clients/listers/api/v1alpha1/floatingip.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/group.go b/pkg/clients/listers/api/v1alpha1/group.go index 33ea8f0f5..1364f5214 100644 --- a/pkg/clients/listers/api/v1alpha1/group.go +++ b/pkg/clients/listers/api/v1alpha1/group.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/image.go b/pkg/clients/listers/api/v1alpha1/image.go index f80691124..d63ba89c8 100644 --- a/pkg/clients/listers/api/v1alpha1/image.go +++ b/pkg/clients/listers/api/v1alpha1/image.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/keypair.go b/pkg/clients/listers/api/v1alpha1/keypair.go index 6283d582e..268c14ac7 100644 --- a/pkg/clients/listers/api/v1alpha1/keypair.go +++ b/pkg/clients/listers/api/v1alpha1/keypair.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/network.go b/pkg/clients/listers/api/v1alpha1/network.go index 3039921cd..cdd26de8a 100644 --- a/pkg/clients/listers/api/v1alpha1/network.go +++ b/pkg/clients/listers/api/v1alpha1/network.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/port.go b/pkg/clients/listers/api/v1alpha1/port.go index 4a1748403..a61984e89 100644 --- a/pkg/clients/listers/api/v1alpha1/port.go +++ b/pkg/clients/listers/api/v1alpha1/port.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/project.go b/pkg/clients/listers/api/v1alpha1/project.go index 56fd8b6a3..c2dd486be 100644 --- a/pkg/clients/listers/api/v1alpha1/project.go +++ b/pkg/clients/listers/api/v1alpha1/project.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/role.go b/pkg/clients/listers/api/v1alpha1/role.go index 2068923b2..c2d62f895 100644 --- a/pkg/clients/listers/api/v1alpha1/role.go +++ b/pkg/clients/listers/api/v1alpha1/role.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/roleassignment.go b/pkg/clients/listers/api/v1alpha1/roleassignment.go new file mode 100644 index 000000000..37c6c7b8d --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/roleassignment.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// RoleAssignmentLister helps list RoleAssignments. +// All objects returned here must be treated as read-only. +type RoleAssignmentLister interface { + // List lists all RoleAssignments in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.RoleAssignment, err error) + // RoleAssignments returns an object that can list and get RoleAssignments. + RoleAssignments(namespace string) RoleAssignmentNamespaceLister + RoleAssignmentListerExpansion +} + +// roleAssignmentLister implements the RoleAssignmentLister interface. +type roleAssignmentLister struct { + listers.ResourceIndexer[*apiv1alpha1.RoleAssignment] +} + +// NewRoleAssignmentLister returns a new RoleAssignmentLister. +func NewRoleAssignmentLister(indexer cache.Indexer) RoleAssignmentLister { + return &roleAssignmentLister{listers.New[*apiv1alpha1.RoleAssignment](indexer, apiv1alpha1.Resource("roleassignment"))} +} + +// RoleAssignments returns an object that can list and get RoleAssignments. +func (s *roleAssignmentLister) RoleAssignments(namespace string) RoleAssignmentNamespaceLister { + return roleAssignmentNamespaceLister{listers.NewNamespaced[*apiv1alpha1.RoleAssignment](s.ResourceIndexer, namespace)} +} + +// RoleAssignmentNamespaceLister helps list and get RoleAssignments. +// All objects returned here must be treated as read-only. +type RoleAssignmentNamespaceLister interface { + // List lists all RoleAssignments in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.RoleAssignment, err error) + // Get retrieves the RoleAssignment from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.RoleAssignment, error) + RoleAssignmentNamespaceListerExpansion +} + +// roleAssignmentNamespaceLister implements the RoleAssignmentNamespaceLister +// interface. +type roleAssignmentNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.RoleAssignment] +} diff --git a/pkg/clients/listers/api/v1alpha1/router.go b/pkg/clients/listers/api/v1alpha1/router.go index 71c3ce837..5adceeb9b 100644 --- a/pkg/clients/listers/api/v1alpha1/router.go +++ b/pkg/clients/listers/api/v1alpha1/router.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/routerinterface.go b/pkg/clients/listers/api/v1alpha1/routerinterface.go index 285c89483..0a3712f4c 100644 --- a/pkg/clients/listers/api/v1alpha1/routerinterface.go +++ b/pkg/clients/listers/api/v1alpha1/routerinterface.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/securitygroup.go b/pkg/clients/listers/api/v1alpha1/securitygroup.go index 7d0748924..5868504a9 100644 --- a/pkg/clients/listers/api/v1alpha1/securitygroup.go +++ b/pkg/clients/listers/api/v1alpha1/securitygroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/server.go b/pkg/clients/listers/api/v1alpha1/server.go index c79cc772a..66d769baa 100644 --- a/pkg/clients/listers/api/v1alpha1/server.go +++ b/pkg/clients/listers/api/v1alpha1/server.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/servergroup.go b/pkg/clients/listers/api/v1alpha1/servergroup.go index d376dc119..a677d2564 100644 --- a/pkg/clients/listers/api/v1alpha1/servergroup.go +++ b/pkg/clients/listers/api/v1alpha1/servergroup.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/service.go b/pkg/clients/listers/api/v1alpha1/service.go index fc5902d0b..46c571406 100644 --- a/pkg/clients/listers/api/v1alpha1/service.go +++ b/pkg/clients/listers/api/v1alpha1/service.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/sharenetwork.go b/pkg/clients/listers/api/v1alpha1/sharenetwork.go new file mode 100644 index 000000000..15c506d75 --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/sharenetwork.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// ShareNetworkLister helps list ShareNetworks. +// All objects returned here must be treated as read-only. +type ShareNetworkLister interface { + // List lists all ShareNetworks in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.ShareNetwork, err error) + // ShareNetworks returns an object that can list and get ShareNetworks. + ShareNetworks(namespace string) ShareNetworkNamespaceLister + ShareNetworkListerExpansion +} + +// shareNetworkLister implements the ShareNetworkLister interface. +type shareNetworkLister struct { + listers.ResourceIndexer[*apiv1alpha1.ShareNetwork] +} + +// NewShareNetworkLister returns a new ShareNetworkLister. +func NewShareNetworkLister(indexer cache.Indexer) ShareNetworkLister { + return &shareNetworkLister{listers.New[*apiv1alpha1.ShareNetwork](indexer, apiv1alpha1.Resource("sharenetwork"))} +} + +// ShareNetworks returns an object that can list and get ShareNetworks. +func (s *shareNetworkLister) ShareNetworks(namespace string) ShareNetworkNamespaceLister { + return shareNetworkNamespaceLister{listers.NewNamespaced[*apiv1alpha1.ShareNetwork](s.ResourceIndexer, namespace)} +} + +// ShareNetworkNamespaceLister helps list and get ShareNetworks. +// All objects returned here must be treated as read-only. +type ShareNetworkNamespaceLister interface { + // List lists all ShareNetworks in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.ShareNetwork, err error) + // Get retrieves the ShareNetwork from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.ShareNetwork, error) + ShareNetworkNamespaceListerExpansion +} + +// shareNetworkNamespaceLister implements the ShareNetworkNamespaceLister +// interface. +type shareNetworkNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.ShareNetwork] +} diff --git a/pkg/clients/listers/api/v1alpha1/subnet.go b/pkg/clients/listers/api/v1alpha1/subnet.go index 751437886..c1f916198 100644 --- a/pkg/clients/listers/api/v1alpha1/subnet.go +++ b/pkg/clients/listers/api/v1alpha1/subnet.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/trunk.go b/pkg/clients/listers/api/v1alpha1/trunk.go new file mode 100644 index 000000000..bd1a34270 --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/trunk.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// TrunkLister helps list Trunks. +// All objects returned here must be treated as read-only. +type TrunkLister interface { + // List lists all Trunks in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.Trunk, err error) + // Trunks returns an object that can list and get Trunks. + Trunks(namespace string) TrunkNamespaceLister + TrunkListerExpansion +} + +// trunkLister implements the TrunkLister interface. +type trunkLister struct { + listers.ResourceIndexer[*apiv1alpha1.Trunk] +} + +// NewTrunkLister returns a new TrunkLister. +func NewTrunkLister(indexer cache.Indexer) TrunkLister { + return &trunkLister{listers.New[*apiv1alpha1.Trunk](indexer, apiv1alpha1.Resource("trunk"))} +} + +// Trunks returns an object that can list and get Trunks. +func (s *trunkLister) Trunks(namespace string) TrunkNamespaceLister { + return trunkNamespaceLister{listers.NewNamespaced[*apiv1alpha1.Trunk](s.ResourceIndexer, namespace)} +} + +// TrunkNamespaceLister helps list and get Trunks. +// All objects returned here must be treated as read-only. +type TrunkNamespaceLister interface { + // List lists all Trunks in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.Trunk, err error) + // Get retrieves the Trunk from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.Trunk, error) + TrunkNamespaceListerExpansion +} + +// trunkNamespaceLister implements the TrunkNamespaceLister +// interface. +type trunkNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.Trunk] +} diff --git a/pkg/clients/listers/api/v1alpha1/user.go b/pkg/clients/listers/api/v1alpha1/user.go new file mode 100644 index 000000000..363b6a371 --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/user.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// UserLister helps list Users. +// All objects returned here must be treated as read-only. +type UserLister interface { + // List lists all Users in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.User, err error) + // Users returns an object that can list and get Users. + Users(namespace string) UserNamespaceLister + UserListerExpansion +} + +// userLister implements the UserLister interface. +type userLister struct { + listers.ResourceIndexer[*apiv1alpha1.User] +} + +// NewUserLister returns a new UserLister. +func NewUserLister(indexer cache.Indexer) UserLister { + return &userLister{listers.New[*apiv1alpha1.User](indexer, apiv1alpha1.Resource("user"))} +} + +// Users returns an object that can list and get Users. +func (s *userLister) Users(namespace string) UserNamespaceLister { + return userNamespaceLister{listers.NewNamespaced[*apiv1alpha1.User](s.ResourceIndexer, namespace)} +} + +// UserNamespaceLister helps list and get Users. +// All objects returned here must be treated as read-only. +type UserNamespaceLister interface { + // List lists all Users in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.User, err error) + // Get retrieves the User from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.User, error) + UserNamespaceListerExpansion +} + +// userNamespaceLister implements the UserNamespaceLister +// interface. +type userNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.User] +} diff --git a/pkg/clients/listers/api/v1alpha1/volume.go b/pkg/clients/listers/api/v1alpha1/volume.go index fda954e65..70d54efc5 100644 --- a/pkg/clients/listers/api/v1alpha1/volume.go +++ b/pkg/clients/listers/api/v1alpha1/volume.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/pkg/clients/listers/api/v1alpha1/volumetype.go b/pkg/clients/listers/api/v1alpha1/volumetype.go index b2bc83536..3dcb8d773 100644 --- a/pkg/clients/listers/api/v1alpha1/volumetype.go +++ b/pkg/clients/listers/api/v1alpha1/volumetype.go @@ -1,5 +1,5 @@ /* -Copyright 2025 The ORC Authors. +Copyright The ORC Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/test/apivalidations/addressscope_test.go b/test/apivalidations/addressscope_test.go new file mode 100644 index 000000000..2ac6246d9 --- /dev/null +++ b/test/apivalidations/addressscope_test.go @@ -0,0 +1,77 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + addressScopeObjName = "addressscope" +) + +func addressScopeStub(namespace *corev1.Namespace) *orcv1alpha1.AddressScope { + obj := &orcv1alpha1.AddressScope{} + obj.Name = addressScopeObjName + obj.Namespace = namespace.Name + return obj +} + +func baseAddressScopePatch(addressScope client.Object) *applyconfigv1alpha1.AddressScopeApplyConfiguration { + return applyconfigv1alpha1.AddressScope(addressScope.GetName(), addressScope.GetNamespace()). + WithSpec(applyconfigv1alpha1.AddressScopeSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +var _ = Describe("ORC AddressScope API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + When("updating the shared field", func() { + It("should permit share a unshared address scope", func(ctx context.Context) { + addressScope := addressScopeStub(namespace) + patch := baseAddressScopePatch(addressScope) + patch.Spec.WithResource(applyconfigv1alpha1.AddressScopeResourceSpec(). + WithIPVersion(orcv1alpha1.IPVersion(4)). + WithShared(false)) + Expect(applyObj(ctx, addressScope, patch)).To(Succeed()) + patch.Spec.WithResource(patch.Spec.Resource).Resource.WithShared(true) + Expect(applyObj(ctx, addressScope, patch)).To(Succeed()) + }) + + It("should not permit unshare a shared address scope", func(ctx context.Context) { + addressScope := addressScopeStub(namespace) + patch := baseAddressScopePatch(addressScope) + patch.Spec.WithResource(applyconfigv1alpha1.AddressScopeResourceSpec(). + WithIPVersion(orcv1alpha1.IPVersion(4)). + WithShared(true)) + Expect(applyObj(ctx, addressScope, patch)).To(Succeed()) + patch.Spec.WithResource(patch.Spec.Resource).Resource.WithShared(false) + Expect(applyObj(ctx, addressScope, patch)).To(MatchError(ContainSubstring("shared address scope can't be unshared"))) + }) + }) +}) diff --git a/test/apivalidations/applicationcredential_test.go b/test/apivalidations/applicationcredential_test.go new file mode 100644 index 000000000..4b6bfc785 --- /dev/null +++ b/test/apivalidations/applicationcredential_test.go @@ -0,0 +1,146 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + applicationcredentialName = "applicationcredential" + applicationcredentialID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae120" +) + +func applicationcredentialStub(namespace *corev1.Namespace) *orcv1alpha1.ApplicationCredential { + obj := &orcv1alpha1.ApplicationCredential{} + obj.Name = applicationcredentialName + obj.Namespace = namespace.Name + return obj +} + +func testApplicationCredentialResource() *applyconfigv1alpha1.ApplicationCredentialResourceSpecApplyConfiguration { + return applyconfigv1alpha1.ApplicationCredentialResourceSpec(). + WithUserRef("user"). + WithSecretRef("applicationcredential-secret") +} + +func baseApplicationCredentialPatch(obj client.Object) *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration { + return applyconfigv1alpha1.ApplicationCredential(obj.GetName(), obj.GetNamespace()). + WithSpec(applyconfigv1alpha1.ApplicationCredentialSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testApplicationCredentialImport() *applyconfigv1alpha1.ApplicationCredentialImportApplyConfiguration { + return applyconfigv1alpha1.ApplicationCredentialImport().WithID(applicationcredentialID) +} + +var _ = Describe("ORC ApplicationCredential API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.ApplicationCredentialApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return applicationcredentialStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration { + return baseApplicationCredentialPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithResource(testApplicationCredentialResource()) + }, + applyImport: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithImport(testApplicationCredentialImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ApplicationCredentialImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ApplicationCredentialImport().WithFilter(applyconfigv1alpha1.ApplicationCredentialFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ApplicationCredentialImport().WithFilter(applyconfigv1alpha1.ApplicationCredentialFilter().WithName("foo").WithUserRef("user"))) + }, + applyManaged: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.ApplicationCredentialApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.ApplicationCredential).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.ApplicationCredential).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a applicationcredential without required fields", func(ctx context.Context) { + obj := applicationcredentialStub(namespace) + patch := baseApplicationCredentialPatch(obj) + patch.Spec.WithResource(applyconfigv1alpha1.ApplicationCredentialResourceSpec()) + Expect(applyObj(ctx, obj, patch)).NotTo(Succeed()) + }) + + It("should be immutable", func(ctx context.Context) { + obj := applicationcredentialStub(namespace) + patch := baseApplicationCredentialPatch(obj) + patch.Spec.WithResource(testApplicationCredentialResource(). + WithUserRef("user-a")) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + + patch.Spec.WithResource(testApplicationCredentialResource(). + WithUserRef("user-b")) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("ApplicationCredentialResourceSpec is immutable"))) + }) + + DescribeTable("should permit valid http method", + func(ctx context.Context, httpmethod orcv1alpha1.HTTPMethod) { + obj := applicationcredentialStub(namespace) + patch := baseApplicationCredentialPatch(obj) + specPatch := applyconfigv1alpha1.ApplicationCredentialAccessRule().WithMethod(httpmethod) + patch.Spec.WithResource(testApplicationCredentialResource().WithAccessRules(specPatch)) + Expect(applyObj(ctx, obj, patch)).To(Succeed(), "create application credential") + }, + Entry(string(orcv1alpha1.HTTPMethodCONNECT), orcv1alpha1.HTTPMethodCONNECT), + Entry(string(orcv1alpha1.HTTPMethodDELETE), orcv1alpha1.HTTPMethodDELETE), + Entry(string(orcv1alpha1.HTTPMethodGET), orcv1alpha1.HTTPMethodGET), + Entry(string(orcv1alpha1.HTTPMethodHEAD), orcv1alpha1.HTTPMethodHEAD), + Entry(string(orcv1alpha1.HTTPMethodOPTIONS), orcv1alpha1.HTTPMethodOPTIONS), + Entry(string(orcv1alpha1.HTTPMethodPATCH), orcv1alpha1.HTTPMethodPATCH), + Entry(string(orcv1alpha1.HTTPMethodPOST), orcv1alpha1.HTTPMethodPOST), + Entry(string(orcv1alpha1.HTTPMethodPUT), orcv1alpha1.HTTPMethodPUT), + Entry(string(orcv1alpha1.HTTPMethodTRACE), orcv1alpha1.HTTPMethodTRACE), + ) + + It("should not permit invalid http method", func(ctx context.Context) { + obj := applicationcredentialStub(namespace) + patch := baseApplicationCredentialPatch(obj) + patch.Spec.WithResource(testApplicationCredentialResource().WithAccessRules(applyconfigv1alpha1.ApplicationCredentialAccessRule().WithMethod("foo"))) + Expect(applyObj(ctx, obj, patch)).NotTo(Succeed(), "create application credential") + }) +}) diff --git a/test/apivalidations/common_test.go b/test/apivalidations/common_test.go index b71099b91..1234705aa 100644 --- a/test/apivalidations/common_test.go +++ b/test/apivalidations/common_test.go @@ -17,6 +17,14 @@ limitations under the License. package apivalidations import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" ) @@ -25,3 +33,127 @@ func testCredentials() *applyconfigv1alpha1.CloudCredentialsReferenceApplyConfig WithSecretName("openstack-credentials"). WithCloudName("openstack") } + +// managementPolicyTestArgs provides resource-specific callbacks for the shared +// management policy validation tests. PatchT is the concrete apply +// configuration type for the resource (e.g. *applyconfigv1alpha1.FlavorApplyConfiguration). +type managementPolicyTestArgs[PatchT any] struct { + // createObject returns a new stub object in the given namespace. + createObject func(*corev1.Namespace) client.Object + // basePatch returns a patch with only cloudCredentialsRef set. + basePatch func(client.Object) PatchT + // applyResource adds a valid resource spec to the patch. + applyResource func(PatchT) + // applyImport adds a valid import (by ID) to the patch. + applyImport func(PatchT) + // applyEmptyImport adds an empty import to the patch. + applyEmptyImport func(PatchT) + // applyEmptyFilter adds an import with an empty filter to the patch. + applyEmptyFilter func(PatchT) + // applyValidFilter adds an import with a valid filter to the patch. + applyValidFilter func(PatchT) + // applyManaged sets the management policy to managed. + applyManaged func(PatchT) + // applyUnmanaged sets the management policy to unmanaged. + applyUnmanaged func(PatchT) + // applyManagedOptions adds managedOptions to the patch. + applyManagedOptions func(PatchT) + // getManagementPolicy reads the management policy from the object. + getManagementPolicy func(client.Object) orcv1alpha1.ManagementPolicy + // getOnDelete reads the onDelete value from the object's managedOptions. + getOnDelete func(client.Object) orcv1alpha1.OnDelete +} + +// runManagementPolicyTests registers shared Ginkgo test cases for the standard +// management policy validations that apply to all ORC resources with a +// managementPolicy field. +func runManagementPolicyTests[PatchT any](getNamespace func() *corev1.Namespace, args managementPolicyTestArgs[PatchT]) { + It("should allow to create a minimal resource and managementPolicy should default to managed", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyResource(patch) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + Expect(args.getManagementPolicy(obj)).To(Equal(orcv1alpha1.ManagementPolicyManaged)) + }) + + It("should require import for unmanaged", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyUnmanaged(patch) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("import must be specified when policy is unmanaged"))) + + args.applyImport(patch) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + }) + + It("should not permit unmanaged with resource", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyUnmanaged(patch) + args.applyImport(patch) + args.applyResource(patch) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("resource may not be specified when policy is unmanaged"))) + }) + + It("should not permit empty import", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyUnmanaged(patch) + args.applyEmptyImport(patch) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("spec.import in body should have at least 1 properties"))) + }) + + It("should not permit empty import filter", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyUnmanaged(patch) + args.applyEmptyFilter(patch) + // Do not force the maximum number of filter properties to be 1 by not hard-coding that string + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("spec.import.filter in body should have at least"))) + }) + + It("should permit valid import filter", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyUnmanaged(patch) + args.applyValidFilter(patch) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + }) + + It("should require resource for managed", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyManaged(patch) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("resource must be specified when policy is managed"))) + + args.applyResource(patch) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + }) + + It("should not permit managed with import", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyImport(patch) + args.applyManaged(patch) + args.applyResource(patch) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("import may not be specified when policy is managed"))) + }) + + It("should not permit managedOptions for unmanaged", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyImport(patch) + args.applyUnmanaged(patch) + args.applyManagedOptions(patch) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("managedOptions may only be provided when policy is managed"))) + }) + + It("should permit managedOptions for managed", func(ctx context.Context) { + obj := args.createObject(getNamespace()) + patch := args.basePatch(obj) + args.applyResource(patch) + args.applyManagedOptions(patch) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + Expect(args.getOnDelete(obj)).To(Equal(orcv1alpha1.OnDelete("detach"))) + }) +} diff --git a/test/apivalidations/domain_test.go b/test/apivalidations/domain_test.go new file mode 100644 index 000000000..4087a60ed --- /dev/null +++ b/test/apivalidations/domain_test.go @@ -0,0 +1,90 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + . "github.com/onsi/ginkgo/v2" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + domainName = "domain" + domainID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae120" +) + +func domainStub(namespace *corev1.Namespace) *orcv1alpha1.Domain { + obj := &orcv1alpha1.Domain{} + obj.Name = domainName + obj.Namespace = namespace.Name + return obj +} + +func testDomainResource() *applyconfigv1alpha1.DomainResourceSpecApplyConfiguration { + return applyconfigv1alpha1.DomainResourceSpec() +} + +func baseDomainPatch(domain client.Object) *applyconfigv1alpha1.DomainApplyConfiguration { + return applyconfigv1alpha1.Domain(domain.GetName(), domain.GetNamespace()). + WithSpec(applyconfigv1alpha1.DomainSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testDomainImport() *applyconfigv1alpha1.DomainImportApplyConfiguration { + return applyconfigv1alpha1.DomainImport().WithID(domainID) +} + +var _ = Describe("ORC Domain API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.DomainApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return domainStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.DomainApplyConfiguration { return baseDomainPatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { p.Spec.WithResource(testDomainResource()) }, + applyImport: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { p.Spec.WithImport(testDomainImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.DomainImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.DomainImport().WithFilter(applyconfigv1alpha1.DomainFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.DomainImport().WithFilter(applyconfigv1alpha1.DomainFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.DomainApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Domain).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Domain).Spec.ManagedOptions.OnDelete + }, + }) +}) diff --git a/test/apivalidations/endpoint_test.go b/test/apivalidations/endpoint_test.go new file mode 100644 index 000000000..b648c66f1 --- /dev/null +++ b/test/apivalidations/endpoint_test.go @@ -0,0 +1,174 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + endpointName = "endpoint" + endpointID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae128" +) + +func endpointStub(namespace *corev1.Namespace) *orcv1alpha1.Endpoint { + obj := &orcv1alpha1.Endpoint{} + obj.Name = endpointName + obj.Namespace = namespace.Name + return obj +} + +func testEndpointResource() *applyconfigv1alpha1.EndpointResourceSpecApplyConfiguration { + return applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("public"). + WithURL("https://example.com"). + WithServiceRef("my-service") +} + +func baseEndpointPatch(endpoint client.Object) *applyconfigv1alpha1.EndpointApplyConfiguration { + return applyconfigv1alpha1.Endpoint(endpoint.GetName(), endpoint.GetNamespace()). + WithSpec(applyconfigv1alpha1.EndpointSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testEndpointImport() *applyconfigv1alpha1.EndpointImportApplyConfiguration { + return applyconfigv1alpha1.EndpointImport().WithID(endpointID) +} + +var _ = Describe("ORC Endpoint API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.EndpointApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return endpointStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.EndpointApplyConfiguration { return baseEndpointPatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { p.Spec.WithResource(testEndpointResource()) }, + applyImport: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { p.Spec.WithImport(testEndpointImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.EndpointImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.EndpointImport().WithFilter(applyconfigv1alpha1.EndpointFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.EndpointImport().WithFilter(applyconfigv1alpha1.EndpointFilter().WithInterface("public"))) + }, + applyManaged: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.EndpointApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Endpoint).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Endpoint).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject an endpoint without required fields", func(ctx context.Context) { + endpoint := endpointStub(namespace) + patch := baseEndpointPatch(endpoint) + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec()) + Expect(applyObj(ctx, endpoint, patch)).NotTo(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("public").WithServiceRef("my-service")) + Expect(applyObj(ctx, endpoint, patch)).To(MatchError(ContainSubstring("spec.resource.url"))) + + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithURL("https://example.com").WithServiceRef("my-service")) + Expect(applyObj(ctx, endpoint, patch)).To(MatchError(ContainSubstring("spec.resource.interface"))) + + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("public").WithURL("https://example.com")) + Expect(applyObj(ctx, endpoint, patch)).To(MatchError(ContainSubstring("spec.resource.serviceRef"))) + }) + + It("should reject invalid interface enum value", func(ctx context.Context) { + endpoint := endpointStub(namespace) + patch := baseEndpointPatch(endpoint) + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("invalid"). + WithURL("https://example.com"). + WithServiceRef("my-service")) + Expect(applyObj(ctx, endpoint, patch)).NotTo(Succeed()) + }) + + DescribeTable("should permit valid interface enum values", + func(ctx context.Context, iface string) { + endpoint := endpointStub(namespace) + patch := baseEndpointPatch(endpoint) + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface(iface). + WithURL("https://example.com"). + WithServiceRef("my-service")) + Expect(applyObj(ctx, endpoint, patch)).To(Succeed()) + }, + Entry("admin", "admin"), + Entry("internal", "internal"), + Entry("public", "public"), + ) + + It("should have immutable serviceRef", func(ctx context.Context) { + endpoint := endpointStub(namespace) + patch := baseEndpointPatch(endpoint) + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("public"). + WithURL("https://example.com"). + WithServiceRef("service-a")) + Expect(applyObj(ctx, endpoint, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("public"). + WithURL("https://example.com"). + WithServiceRef("service-b")) + Expect(applyObj(ctx, endpoint, patch)).To(MatchError(ContainSubstring("serviceRef is immutable"))) + }) + + It("should have immutable description", func(ctx context.Context) { + endpoint := endpointStub(namespace) + patch := baseEndpointPatch(endpoint) + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("public"). + WithURL("https://example.com"). + WithServiceRef("my-service"). + WithDescription("desc-a")) + Expect(applyObj(ctx, endpoint, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.EndpointResourceSpec(). + WithInterface("public"). + WithURL("https://example.com"). + WithServiceRef("my-service"). + WithDescription("desc-b")) + Expect(applyObj(ctx, endpoint, patch)).To(MatchError(ContainSubstring("description is immutable"))) + }) +}) diff --git a/test/apivalidations/flavor_test.go b/test/apivalidations/flavor_test.go index 322050abe..25f4659fe 100644 --- a/test/apivalidations/flavor_test.go +++ b/test/apivalidations/flavor_test.go @@ -51,12 +51,6 @@ func baseFlavorPatch(flavor client.Object) *applyconfigv1alpha1.FlavorApplyConfi WithCloudCredentialsRef(testCredentials())) } -func baseWorkingFlavorPatch(flavor client.Object) *applyconfigv1alpha1.FlavorApplyConfiguration { - patch := baseFlavorPatch(flavor) - patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithRAM(1).WithVcpus(1).WithDisk(1)) - return patch -} - func testFlavorImport() *applyconfigv1alpha1.FlavorImportApplyConfiguration { return applyconfigv1alpha1.FlavorImport().WithID(flavorID) } @@ -67,21 +61,88 @@ var _ = Describe("ORC Flavor API validations", func() { namespace = createNamespace() }) - It("should allow to create a minimal flavor and managementPolicy should default to managed", func(ctx context.Context) { + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.FlavorApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return flavorStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.FlavorApplyConfiguration { + return baseFlavorPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithResource(testFlavorResource()) + }, + applyImport: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithImport(testFlavorImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.FlavorImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.FlavorImport().WithFilter(applyconfigv1alpha1.FlavorFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.FlavorImport().WithFilter(applyconfigv1alpha1.FlavorFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.FlavorApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Flavor).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Flavor).Spec.ManagedOptions.OnDelete + }, + }) + + It("should be immutable except extraSpecs", func(ctx context.Context) { flavor := flavorStub(namespace) - patch := baseFlavorPatch(flavor) - patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithRAM(1).WithVcpus(1).WithDisk(1)) - Expect(applyObj(ctx, flavor, patch)).To(Succeed()) - Expect(flavor.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) - }) - It("should be immutable", func(ctx context.Context) { - flavor := flavorStub(namespace) patch := baseFlavorPatch(flavor) - patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithRAM(1).WithVcpus(1).WithDisk(1)) + patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec(). + WithName("base-name"). + WithID("base-id"). + WithDescription("base-desc"). + WithRAM(1). + WithVcpus(1). + WithDisk(1). + WithSwap(1). + WithIsPublic(true). + WithEphemeral(1). + WithExtraSpecs( + applyconfigv1alpha1.FlavorExtraSpec(). + WithName("spec"). + WithValue("specValue"), + ), + ) Expect(applyObj(ctx, flavor, patch)).To(Succeed()) - patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithRAM(2).WithVcpus(1).WithDisk(1)) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("FlavorResourceSpec is immutable"))) + + patch = baseFlavorPatch(flavor) + patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec(). + WithName("mutated-name"). + WithID("mutated-id"). + WithDescription("mutated-desc"). + WithRAM(2). + WithVcpus(2). + WithDisk(2). + WithSwap(2). + WithIsPublic(false). + WithEphemeral(2). + WithExtraSpecs( + applyconfigv1alpha1.FlavorExtraSpec(). + WithName("spec2"). + WithValue("specValue2"), + ), + ) + err := applyObj(ctx, flavor, patch) + fields := []string{"name", "id", "description", "ram", "vcpus", "disk", "swap", "isPublic", "ephemeral"} + for _, field := range fields { + Expect(err).To(MatchError(ContainSubstring(field + " is immutable"))) + } + Expect(err.Error()).To(Not(ContainSubstring("extraSpecs is immutable"))) }) It("should reject a flavor without required fields", func(ctx context.Context) { @@ -114,71 +175,6 @@ var _ = Describe("ORC Flavor API validations", func() { maxString := strings.Repeat("a", 65536) patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithRAM(1).WithVcpus(1).WithDescription(maxString)) Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.description: Too long"))) - - }) - It("should default to managementPolicy managed", func(ctx context.Context) { - flavor := flavorStub(namespace) - flavor.Spec.Resource = &orcv1alpha1.FlavorResourceSpec{ - RAM: 1, - Vcpus: 1, - } - flavor.Spec.CloudCredentialsRef = orcv1alpha1.CloudCredentialsReference{ - SecretName: "my-secret", - CloudName: "my-cloud", - } - - Expect(k8sClient.Create(ctx, flavor)).To(Succeed()) - Expect(flavor.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) - }) - - It("should require import for unmanaged", func(ctx context.Context) { - flavor := flavorStub(namespace) - patch := baseFlavorPatch(flavor) - patch.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("import must be specified when policy is unmanaged"))) - - patch.Spec.WithImport(testFlavorImport()) - Expect(applyObj(ctx, flavor, patch)).To(Succeed()) - }) - - It("should not permit unmanaged with resource", func(ctx context.Context) { - flavor := flavorStub(namespace) - patch := baseFlavorPatch(flavor) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(testFlavorImport()). - WithResource(testFlavorResource()) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("resource may not be specified when policy is unmanaged"))) - }) - - It("should not permit empty import", func(ctx context.Context) { - flavor := flavorStub(namespace) - patch := baseFlavorPatch(flavor) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.FlavorImport()) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.import in body should have at least 1 properties"))) - }) - - It("should not permit empty import filter", func(ctx context.Context) { - flavor := flavorStub(namespace) - patch := baseFlavorPatch(flavor) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.FlavorImport(). - WithFilter(applyconfigv1alpha1.FlavorFilter())) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.import.filter in body should have at least 1 properties"))) - }) - - It("should permit import filter with values within bound", func(ctx context.Context) { - flavor := flavorStub(namespace) - patch := baseFlavorPatch(flavor) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.FlavorImport(). - WithFilter(applyconfigv1alpha1.FlavorFilter(). - WithName("foo").WithRAM(1))) - Expect(applyObj(ctx, flavor, patch)).To(Succeed()) }) It("should reject import filter with value less than minimal", func(ctx context.Context) { @@ -191,44 +187,28 @@ var _ = Describe("ORC Flavor API validations", func() { Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.import.filter.ram in body should be greater than or equal to 1"))) }) - It("should require resource for managed", func(ctx context.Context) { + It("should reject flavor IDs which are not according to the specified regex", func(ctx context.Context) { flavor := flavorStub(namespace) patch := baseFlavorPatch(flavor) - patch.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("resource must be specified when policy is managed"))) - - patch.Spec.WithResource(testFlavorResource()) + maxString := strings.Repeat("a", 256) + patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID(" test").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1)) + Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id: Invalid value"))) + patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID("test ").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1)) + Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id: Invalid value"))) + patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID(maxString).WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1)) + Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id: Too long"))) + patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID("").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1)) + Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("spec.resource.id in body should be at least 1 chars long"))) + patch.Spec.WithResource(applyconfigv1alpha1.FlavorResourceSpec().WithID("test.id -123_").WithRAM(1).WithVcpus(1).WithDescription("test").WithDisk(1)) Expect(applyObj(ctx, flavor, patch)).To(Succeed()) }) - It("should not permit managed with import", func(ctx context.Context) { - flavor := flavorStub(namespace) - patch := baseFlavorPatch(flavor) - patch.Spec. - WithImport(testFlavorImport()). - WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged). - WithResource(testFlavorResource()) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("import may not be specified when policy is managed"))) - }) - - It("should not permit managedOptions for unmanaged", func(ctx context.Context) { + It("should permit extraSpecs with required fields", func(ctx context.Context) { flavor := flavorStub(namespace) patch := baseFlavorPatch(flavor) - patch.Spec. - WithImport(testFlavorImport()). - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithManagedOptions(applyconfigv1alpha1.ManagedOptions(). - WithOnDelete(orcv1alpha1.OnDeleteDetach)) - Expect(applyObj(ctx, flavor, patch)).To(MatchError(ContainSubstring("managedOptions may only be provided when policy is managed"))) - }) - - It("should permit managedOptions for managed", func(ctx context.Context) { - flavor := flavorStub(namespace) - patch := baseWorkingFlavorPatch(flavor) - patch.Spec. - WithManagedOptions(applyconfigv1alpha1.ManagedOptions(). - WithOnDelete(orcv1alpha1.OnDeleteDetach)) + patch.Spec.WithResource(testFlavorResource(). + WithExtraSpecs(applyconfigv1alpha1.FlavorExtraSpec(). + WithName("key").WithValue("value"))) Expect(applyObj(ctx, flavor, patch)).To(Succeed()) - Expect(flavor.Spec.ManagedOptions.OnDelete).To(Equal(orcv1alpha1.OnDelete("detach"))) }) }) diff --git a/test/apivalidations/floatingip_test.go b/test/apivalidations/floatingip_test.go new file mode 100644 index 000000000..58295cf2f --- /dev/null +++ b/test/apivalidations/floatingip_test.go @@ -0,0 +1,172 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + floatingIPName = "floatingip" + floatingIPID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae130" +) + +func floatingIPStub(namespace *corev1.Namespace) *orcv1alpha1.FloatingIP { + obj := &orcv1alpha1.FloatingIP{} + obj.Name = floatingIPName + obj.Namespace = namespace.Name + return obj +} + +func testFloatingIPResource() *applyconfigv1alpha1.FloatingIPResourceSpecApplyConfiguration { + return applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("my-network") +} + +func baseFloatingIPPatch(fip client.Object) *applyconfigv1alpha1.FloatingIPApplyConfiguration { + return applyconfigv1alpha1.FloatingIP(fip.GetName(), fip.GetNamespace()). + WithSpec(applyconfigv1alpha1.FloatingIPSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testFloatingIPImport() *applyconfigv1alpha1.FloatingIPImportApplyConfiguration { + return applyconfigv1alpha1.FloatingIPImport().WithID(floatingIPID) +} + +var _ = Describe("ORC FloatingIP API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.FloatingIPApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return floatingIPStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.FloatingIPApplyConfiguration { + return baseFloatingIPPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithResource(testFloatingIPResource()) + }, + applyImport: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithImport(testFloatingIPImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.FloatingIPImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.FloatingIPImport().WithFilter(applyconfigv1alpha1.FloatingIPFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.FloatingIPImport().WithFilter(applyconfigv1alpha1.FloatingIPFilter().WithFloatingNetworkRef("my-network"))) + }, + applyManaged: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.FloatingIPApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.FloatingIP).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.FloatingIP).Spec.ManagedOptions.OnDelete + }, + }) + + It("should require exactly one of floatingNetworkRef or floatingSubnetRef", func(ctx context.Context) { + fip := floatingIPStub(namespace) + patch := baseFloatingIPPatch(fip) + + // Neither set + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec()) + Expect(applyObj(ctx, fip, patch)).To(MatchError(ContainSubstring("Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' must be set"))) + + // Both set + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("net-a"). + WithFloatingSubnetRef("subnet-a")) + Expect(applyObj(ctx, fip, patch)).To(MatchError(ContainSubstring("Exactly one of 'floatingNetworkRef' or 'floatingSubnetRef' must be set"))) + + // Only floatingSubnetRef set - should succeed + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingSubnetRef("subnet-a")) + Expect(applyObj(ctx, fip, patch)).To(Succeed()) + }) + + It("should have immutable floatingNetworkRef", func(ctx context.Context) { + fip := floatingIPStub(namespace) + patch := baseFloatingIPPatch(fip) + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("net-a")) + Expect(applyObj(ctx, fip, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("net-b")) + Expect(applyObj(ctx, fip, patch)).To(MatchError(ContainSubstring("floatingNetworkRef is immutable"))) + }) + + It("should have immutable floatingSubnetRef", func(ctx context.Context) { + fip := floatingIPStub(namespace) + patch := baseFloatingIPPatch(fip) + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingSubnetRef("subnet-a")) + Expect(applyObj(ctx, fip, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingSubnetRef("subnet-b")) + Expect(applyObj(ctx, fip, patch)).To(MatchError(ContainSubstring("floatingSubnetRef is immutable"))) + }) + + It("should have immutable portRef", func(ctx context.Context) { + fip := floatingIPStub(namespace) + patch := baseFloatingIPPatch(fip) + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("my-network"). + WithPortRef("port-a")) + Expect(applyObj(ctx, fip, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("my-network"). + WithPortRef("port-b")) + Expect(applyObj(ctx, fip, patch)).To(MatchError(ContainSubstring("portRef is immutable"))) + }) + + It("should have immutable projectRef", func(ctx context.Context) { + fip := floatingIPStub(namespace) + patch := baseFloatingIPPatch(fip) + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("my-network"). + WithProjectRef("project-a")) + Expect(applyObj(ctx, fip, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.FloatingIPResourceSpec(). + WithFloatingNetworkRef("my-network"). + WithProjectRef("project-b")) + Expect(applyObj(ctx, fip, patch)).To(MatchError(ContainSubstring("projectRef is immutable"))) + }) +}) diff --git a/test/apivalidations/group_test.go b/test/apivalidations/group_test.go new file mode 100644 index 000000000..e322615ae --- /dev/null +++ b/test/apivalidations/group_test.go @@ -0,0 +1,111 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + groupName = "group" + groupID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae122" +) + +func groupStub(namespace *corev1.Namespace) *orcv1alpha1.Group { + obj := &orcv1alpha1.Group{} + obj.Name = groupName + obj.Namespace = namespace.Name + return obj +} + +func testGroupResource() *applyconfigv1alpha1.GroupResourceSpecApplyConfiguration { + return applyconfigv1alpha1.GroupResourceSpec() +} + +func baseGroupPatch(group client.Object) *applyconfigv1alpha1.GroupApplyConfiguration { + return applyconfigv1alpha1.Group(group.GetName(), group.GetNamespace()). + WithSpec(applyconfigv1alpha1.GroupSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testGroupImport() *applyconfigv1alpha1.GroupImportApplyConfiguration { + return applyconfigv1alpha1.GroupImport().WithID(groupID) +} + +var _ = Describe("ORC Group API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, + managementPolicyTestArgs[*applyconfigv1alpha1.GroupApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return groupStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.GroupApplyConfiguration { return baseGroupPatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithResource(testGroupResource()) + }, + applyImport: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithImport(testGroupImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.GroupImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.GroupImport().WithFilter(applyconfigv1alpha1.GroupFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.GroupImport().WithFilter(applyconfigv1alpha1.GroupFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.GroupApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Group).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Group).Spec.ManagedOptions.OnDelete + }, + }, + ) + + It("should have immutable domainRef", func(ctx context.Context) { + group := groupStub(namespace) + patch := baseGroupPatch(group) + patch.Spec.WithResource(applyconfigv1alpha1.GroupResourceSpec(). + WithDomainRef("domain-a")) + Expect(applyObj(ctx, group, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.GroupResourceSpec(). + WithDomainRef("domain-b")) + Expect(applyObj(ctx, group, patch)).To(MatchError(ContainSubstring("domainRef is immutable"))) + }) +}) diff --git a/test/apivalidations/image_test.go b/test/apivalidations/image_test.go index e9159b580..3d192fb84 100644 --- a/test/apivalidations/image_test.go +++ b/test/apivalidations/image_test.go @@ -108,6 +108,43 @@ var _ = Describe("ORC Image API validations", func() { namespace = createNamespace() }) + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.ImageApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return imageStub("image", ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.ImageApplyConfiguration { + return basePatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithResource(testImageResource()) + }, + applyImport: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithImport(testImageImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ImageImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ImageImport().WithFilter(applyconfigv1alpha1.ImageFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ImageImport().WithFilter(applyconfigv1alpha1.ImageFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.ImageApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Image).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Image).Spec.ManagedOptions.OnDelete + }, + }) + It("should allow to create a minimal image", func(ctx context.Context) { image := imageStub("image", namespace) minimalPatch := minimalManagedPatch(image) @@ -115,93 +152,6 @@ var _ = Describe("ORC Image API validations", func() { Expect(applyObj(ctx, image, minimalPatch)).To(Succeed()) }) - It("should default to managementPolicy managed", func(ctx context.Context) { - image := imageStub("image", namespace) - image.Spec.Resource = &orcv1alpha1.ImageResourceSpec{ - Content: &orcv1alpha1.ImageContent{ - DiskFormat: orcv1alpha1.ImageDiskFormatQCOW2, - Download: &orcv1alpha1.ImageContentSourceDownload{ - URL: "https://example.com/example.img", - }, - }, - } - image.Spec.CloudCredentialsRef = orcv1alpha1.CloudCredentialsReference{ - SecretName: "my-secret", - CloudName: "my-cloud", - } - - Expect(k8sClient.Create(ctx, image)).To(Succeed()) - Expect(image.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) - }) - - It("should require import for unmanaged", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) - Expect(applyObj(ctx, image, patch)).NotTo(Succeed()) - - patch.Spec.WithImport(testImageImport()) - Expect(applyObj(ctx, image, patch)).To(Succeed()) - }) - - It("should not permit unmanaged with resource", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(testImageImport()). - WithResource(testImageResource()) - }) - - It("should not permit empty import", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.ImageImport()) - Expect(applyObj(ctx, image, patch)).NotTo(Succeed()) - }) - - It("should not permit empty import filter", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.ImageImport(). - WithFilter(applyconfigv1alpha1.ImageFilter())) - Expect(applyObj(ctx, image, patch)).NotTo(Succeed()) - }) - - It("should permit import filter with name", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.ImageImport(). - WithFilter(applyconfigv1alpha1.ImageFilter().WithName("foo"))) - Expect(applyObj(ctx, image, patch)).To(Succeed()) - }) - - It("should require resource for managed", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) - Expect(applyObj(ctx, image, patch)).NotTo(Succeed()) - - patch.Spec.WithResource(testImageResource()) - Expect(applyObj(ctx, image, patch)).To(Succeed()) - }) - - It("should not permit managed with import", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec. - WithImport(testImageImport()). - WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged). - WithResource(testImageResource()) - Expect(applyObj(ctx, image, patch)).NotTo(Succeed()) - }) - It("should require content when not importing", func(ctx context.Context) { image := imageStub("image", namespace) patch := minimalManagedPatch(image) @@ -209,27 +159,6 @@ var _ = Describe("ORC Image API validations", func() { Expect(applyObj(ctx, image, patch)).NotTo(Succeed()) }) - It("should not permit managedOptions for unmanaged", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := basePatch(image) - patch.Spec. - WithImport(testImageImport()). - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithManagedOptions(applyconfigv1alpha1.ManagedOptions(). - WithOnDelete(orcv1alpha1.OnDeleteDetach)) - Expect(applyObj(ctx, image, patch)).NotTo(Succeed()) - }) - - It("should permit managedOptions for managed", func(ctx context.Context) { - image := imageStub("image", namespace) - patch := minimalManagedPatch(image) - patch.Spec. - WithManagedOptions(applyconfigv1alpha1.ManagedOptions(). - WithOnDelete(orcv1alpha1.OnDeleteDetach)) - Expect(applyObj(ctx, image, patch)).To(Succeed()) - Expect(image.Spec.ManagedOptions.OnDelete).To(Equal(orcv1alpha1.OnDelete("detach"))) - }) - DescribeTable("should permit containerFormat", func(ctx context.Context, containerFormat orcv1alpha1.ImageContainerFormat) { image := imageStub("image", namespace) diff --git a/test/apivalidations/keypair_test.go b/test/apivalidations/keypair_test.go new file mode 100644 index 000000000..bb0e9f618 --- /dev/null +++ b/test/apivalidations/keypair_test.go @@ -0,0 +1,127 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + keypairName = "keypair" + keypairID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae124" +) + +func keypairStub(namespace *corev1.Namespace) *orcv1alpha1.KeyPair { + obj := &orcv1alpha1.KeyPair{} + obj.Name = keypairName + obj.Namespace = namespace.Name + return obj +} + +func testKeypairResource() *applyconfigv1alpha1.KeyPairResourceSpecApplyConfiguration { + return applyconfigv1alpha1.KeyPairResourceSpec().WithPublicKey("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ") +} + +func baseKeypairPatch(keypair client.Object) *applyconfigv1alpha1.KeyPairApplyConfiguration { + return applyconfigv1alpha1.KeyPair(keypair.GetName(), keypair.GetNamespace()). + WithSpec(applyconfigv1alpha1.KeyPairSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testKeypairImport() *applyconfigv1alpha1.KeyPairImportApplyConfiguration { + return applyconfigv1alpha1.KeyPairImport().WithID(keypairID) +} + +var _ = Describe("ORC KeyPair API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.KeyPairApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return keypairStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.KeyPairApplyConfiguration { return baseKeypairPatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { p.Spec.WithResource(testKeypairResource()) }, + applyImport: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { p.Spec.WithImport(testKeypairImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.KeyPairImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.KeyPairImport().WithFilter(applyconfigv1alpha1.KeyPairFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.KeyPairImport().WithFilter(applyconfigv1alpha1.KeyPairFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.KeyPairApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.KeyPair).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.KeyPair).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a keypair without required field publicKey", func(ctx context.Context) { + keypair := keypairStub(namespace) + patch := baseKeypairPatch(keypair) + patch.Spec.WithResource(applyconfigv1alpha1.KeyPairResourceSpec()) + Expect(applyObj(ctx, keypair, patch)).To(MatchError(ContainSubstring("spec.resource.publicKey"))) + }) + + It("should reject invalid type enum value", func(ctx context.Context) { + keypair := keypairStub(namespace) + patch := baseKeypairPatch(keypair) + patch.Spec.WithResource(applyconfigv1alpha1.KeyPairResourceSpec(). + WithPublicKey("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ"). + WithType("invalid")) + Expect(applyObj(ctx, keypair, patch)).NotTo(Succeed()) + }) + + It("should permit valid type enum values", func(ctx context.Context) { + keypair := keypairStub(namespace) + patch := baseKeypairPatch(keypair) + patch.Spec.WithResource(applyconfigv1alpha1.KeyPairResourceSpec(). + WithPublicKey("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ"). + WithType("ssh")) + Expect(applyObj(ctx, keypair, patch)).To(Succeed()) + }) + + It("should reject publicKey exceeding max length", func(ctx context.Context) { + keypair := keypairStub(namespace) + patch := baseKeypairPatch(keypair) + patch.Spec.WithResource(applyconfigv1alpha1.KeyPairResourceSpec(). + WithPublicKey(strings.Repeat("a", 16385))) + Expect(applyObj(ctx, keypair, patch)).To(MatchError(ContainSubstring("spec.resource.publicKey"))) + }) +}) diff --git a/test/apivalidations/network_test.go b/test/apivalidations/network_test.go index 58cfb0ebb..7ca8e925e 100644 --- a/test/apivalidations/network_test.go +++ b/test/apivalidations/network_test.go @@ -40,6 +40,14 @@ func networkStub(namespace *corev1.Namespace) *orcv1alpha1.Network { return obj } +func testNetworkResource() *applyconfigv1alpha1.NetworkResourceSpecApplyConfiguration { + return applyconfigv1alpha1.NetworkResourceSpec() +} + +func testNetworkImport() *applyconfigv1alpha1.NetworkImportApplyConfiguration { + return applyconfigv1alpha1.NetworkImport().WithID(networkID) +} + func baseNetworkPatch(network client.Object) *applyconfigv1alpha1.NetworkApplyConfiguration { return applyconfigv1alpha1.Network(network.GetName(), network.GetNamespace()). WithSpec(applyconfigv1alpha1.NetworkSpec(). @@ -52,12 +60,41 @@ var _ = Describe("ORC Network API validations", func() { namespace = createNamespace() }) - It("should allow to create a minimal network and managementPolicy should default to managed", func(ctx context.Context) { - network := networkStub(namespace) - patch := baseNetworkPatch(network) - patch.Spec.WithResource(applyconfigv1alpha1.NetworkResourceSpec()) - Expect(applyObj(ctx, network, patch)).To(Succeed()) - Expect(network.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.NetworkApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return networkStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.NetworkApplyConfiguration { + return baseNetworkPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithResource(testNetworkResource()) + }, + applyImport: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithImport(testNetworkImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.NetworkImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.NetworkImport().WithFilter(applyconfigv1alpha1.NetworkFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.NetworkImport().WithFilter(applyconfigv1alpha1.NetworkFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.NetworkApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Network).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Network).Spec.ManagedOptions.OnDelete + }, }) DescribeTable("should permit valid DNS domain", @@ -152,16 +189,6 @@ var _ = Describe("ORC Network API validations", func() { Expect(applyObj(ctx, network, patch)).To(Succeed()) }) - It("should not permit empty import filter", func(ctx context.Context) { - network := networkStub(namespace) - patch := baseNetworkPatch(network) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.NetworkImport(). - WithFilter(applyconfigv1alpha1.NetworkFilter())) - Expect(applyObj(ctx, network, patch)).NotTo(Succeed()) - }) - It("should not permit invalid import filter", func(ctx context.Context) { network := networkStub(namespace) patch := baseNetworkPatch(network) diff --git a/test/apivalidations/port_test.go b/test/apivalidations/port_test.go index 3c36dea83..b8fb5c074 100644 --- a/test/apivalidations/port_test.go +++ b/test/apivalidations/port_test.go @@ -42,6 +42,14 @@ func portStub(namespace *corev1.Namespace) *orcv1alpha1.Port { return obj } +func testPortResource() *applyconfigv1alpha1.PortResourceSpecApplyConfiguration { + return applyconfigv1alpha1.PortResourceSpec().WithNetworkRef(networkName) +} + +func testPortImport() *applyconfigv1alpha1.PortImportApplyConfiguration { + return applyconfigv1alpha1.PortImport().WithID(portID) +} + func basePortPatch(port client.Object) *applyconfigv1alpha1.PortApplyConfiguration { return applyconfigv1alpha1.Port(port.GetName(), port.GetNamespace()). WithSpec(applyconfigv1alpha1.PortSpec(). @@ -54,12 +62,41 @@ var _ = Describe("ORC Port API validations", func() { namespace = createNamespace() }) - It("should allow to create a minimal port and managementPolicy should default to managed", func(ctx context.Context) { - port := portStub(namespace) - patch := basePortPatch(port) - patch.Spec.WithResource(applyconfigv1alpha1.PortResourceSpec().WithNetworkRef(networkName)) - Expect(applyObj(ctx, port, patch)).To(Succeed()) - Expect(port.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.PortApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return portStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.PortApplyConfiguration { + return basePortPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithResource(testPortResource()) + }, + applyImport: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithImport(testPortImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.PortImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.PortImport().WithFilter(applyconfigv1alpha1.PortFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.PortImport().WithFilter(applyconfigv1alpha1.PortFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.PortApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Port).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Port).Spec.ManagedOptions.OnDelete + }, }) It("should allow to create a port with securityGroupRefs when portSecurity is enabled", func(ctx context.Context) { @@ -70,7 +107,7 @@ var _ = Describe("ORC Port API validations", func() { WithSecurityGroupRefs("sg-foo"). WithPortSecurity(orcv1alpha1.PortSecurityEnabled)) Expect(applyObj(ctx, port, patch)).To(Succeed()) - Expect(port.Spec.Resource.SecurityGroupRefs).To(Equal([]orcv1alpha1.OpenStackName{"sg-foo"})) + Expect(port.Spec.Resource.SecurityGroupRefs).To(Equal([]orcv1alpha1.KubernetesNameRef{"sg-foo"})) Expect(port.Spec.Resource.PortSecurity).To(Equal(orcv1alpha1.PortSecurityEnabled)) }) @@ -123,6 +160,44 @@ var _ = Describe("ORC Port API validations", func() { Expect(applyObj(ctx, port, patch)).To(MatchError(ContainSubstring("spec.resource.vnicType: Too long: may not be longer than 64"))) }) + It("should not allow hostID to be modified", func(ctx context.Context) { + port := portStub(namespace) + patch := basePortPatch(port) + patch.Spec.WithResource(applyconfigv1alpha1.PortResourceSpec(). + WithNetworkRef(networkName). + WithHostID(applyconfigv1alpha1.HostID().WithID("host-a"))) + Expect(applyObj(ctx, port, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.PortResourceSpec(). + WithNetworkRef(networkName). + WithHostID(applyconfigv1alpha1.HostID().WithID("host-b"))) + Expect(applyObj(ctx, port, patch)).To(MatchError(ContainSubstring("hostID is immutable"))) + }) + + It("should not allow valueSpecs to be modified", func(ctx context.Context) { + port := portStub(namespace) + patch := basePortPatch(port) + patch.Spec.WithResource(applyconfigv1alpha1.PortResourceSpec(). + WithNetworkRef(networkName). + WithValueSpecs(applyconfigv1alpha1.PortValueSpec().WithKey("test-key").WithValue("test-value"))) + Expect(applyObj(ctx, port, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.PortResourceSpec(). + WithNetworkRef(networkName). + WithValueSpecs(applyconfigv1alpha1.PortValueSpec().WithKey("test-key").WithValue("test-value-updated"))) + Expect(applyObj(ctx, port, patch)).To(MatchError(ContainSubstring("valueSpecs is immutable"))) + }) + + It("should not allow valueSpecs to have duplicate keys", func(ctx context.Context) { + port := portStub(namespace) + patch := basePortPatch(port) + patch.Spec.WithResource(applyconfigv1alpha1.PortResourceSpec(). + WithNetworkRef(networkName). + WithValueSpecs(applyconfigv1alpha1.PortValueSpec().WithKey("test-key").WithValue("test-value-1")). + WithValueSpecs(applyconfigv1alpha1.PortValueSpec().WithKey("test-key").WithValue("test-value-2"))) + Expect(applyObj(ctx, port, patch)).To(MatchError(ContainSubstring("duplicate entries for key"))) + }) + // Note: we can't create a test for when the portSecurity is set to Inherit and the securityGroupRefs are set, because // the validation is done in the OpenStack API and not in the ORC API. The OpenStack API will return an error if // the network has port security disabled and the port has security group references. diff --git a/test/apivalidations/project_test.go b/test/apivalidations/project_test.go new file mode 100644 index 000000000..745a38400 --- /dev/null +++ b/test/apivalidations/project_test.go @@ -0,0 +1,121 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + projectObjName = "project" + projectID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae125" +) + +func projectStub(namespace *corev1.Namespace) *orcv1alpha1.Project { + obj := &orcv1alpha1.Project{} + obj.Name = projectObjName + obj.Namespace = namespace.Name + return obj +} + +func testProjectResource() *applyconfigv1alpha1.ProjectResourceSpecApplyConfiguration { + return applyconfigv1alpha1.ProjectResourceSpec() +} + +func baseProjectPatch(project client.Object) *applyconfigv1alpha1.ProjectApplyConfiguration { + return applyconfigv1alpha1.Project(project.GetName(), project.GetNamespace()). + WithSpec(applyconfigv1alpha1.ProjectSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testProjectImport() *applyconfigv1alpha1.ProjectImportApplyConfiguration { + return applyconfigv1alpha1.ProjectImport().WithID(projectID) +} + +var _ = Describe("ORC Project API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.ProjectApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return projectStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.ProjectApplyConfiguration { return baseProjectPatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { p.Spec.WithResource(testProjectResource()) }, + applyImport: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { p.Spec.WithImport(testProjectImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ProjectImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ProjectImport().WithFilter(applyconfigv1alpha1.ProjectFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ProjectImport().WithFilter(applyconfigv1alpha1.ProjectFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.ProjectApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Project).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Project).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject duplicate tags", func(ctx context.Context) { + project := projectStub(namespace) + patch := baseProjectPatch(project) + patch.Spec.WithResource(applyconfigv1alpha1.ProjectResourceSpec(). + WithTags("foo", "bar", "foo")) + Expect(applyObj(ctx, project, patch)).NotTo(Succeed()) + }) + + It("should permit unique tags", func(ctx context.Context) { + project := projectStub(namespace) + patch := baseProjectPatch(project) + patch.Spec.WithResource(applyconfigv1alpha1.ProjectResourceSpec(). + WithTags("foo", "bar")) + Expect(applyObj(ctx, project, patch)).To(Succeed()) + }) + + It("should have immutable domainRef", func(ctx context.Context) { + project := projectStub(namespace) + patch := baseProjectPatch(project) + patch.Spec.WithResource(applyconfigv1alpha1.ProjectResourceSpec(). + WithDomainRef("domain-a")) + Expect(applyObj(ctx, project, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.ProjectResourceSpec(). + WithDomainRef("domain-b")) + Expect(applyObj(ctx, project, patch)).To(MatchError(ContainSubstring("domainRef is immutable"))) + }) +}) diff --git a/test/apivalidations/role_test.go b/test/apivalidations/role_test.go new file mode 100644 index 000000000..638dad6d1 --- /dev/null +++ b/test/apivalidations/role_test.go @@ -0,0 +1,111 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + roleName = "role" + roleID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae121" +) + +func roleStub(namespace *corev1.Namespace) *orcv1alpha1.Role { + obj := &orcv1alpha1.Role{} + obj.Name = roleName + obj.Namespace = namespace.Name + return obj +} + +func testRoleResource() *applyconfigv1alpha1.RoleResourceSpecApplyConfiguration { + return applyconfigv1alpha1.RoleResourceSpec() +} + +func baseRolePatch(role client.Object) *applyconfigv1alpha1.RoleApplyConfiguration { + return applyconfigv1alpha1.Role(role.GetName(), role.GetNamespace()). + WithSpec(applyconfigv1alpha1.RoleSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testRoleImport() *applyconfigv1alpha1.RoleImportApplyConfiguration { + return applyconfigv1alpha1.RoleImport().WithID(roleID) +} + +var _ = Describe("ORC Role API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, + managementPolicyTestArgs[*applyconfigv1alpha1.RoleApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return roleStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.RoleApplyConfiguration { return baseRolePatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithResource(testRoleResource()) + }, + applyImport: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithImport(testRoleImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RoleImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RoleImport().WithFilter(applyconfigv1alpha1.RoleFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RoleImport().WithFilter(applyconfigv1alpha1.RoleFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.RoleApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Role).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Role).Spec.ManagedOptions.OnDelete + }, + }, + ) + + It("should have immutable domainRef", func(ctx context.Context) { + role := roleStub(namespace) + patch := baseRolePatch(role) + patch.Spec.WithResource(applyconfigv1alpha1.RoleResourceSpec(). + WithDomainRef("domain-a")) + Expect(applyObj(ctx, role, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.RoleResourceSpec(). + WithDomainRef("domain-b")) + Expect(applyObj(ctx, role, patch)).To(MatchError(ContainSubstring("domainRef is immutable"))) + }) +}) diff --git a/test/apivalidations/roleassignment_test.go b/test/apivalidations/roleassignment_test.go new file mode 100644 index 000000000..a48ba150a --- /dev/null +++ b/test/apivalidations/roleassignment_test.go @@ -0,0 +1,135 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + roleassignmentName = "roleassignment" +) + +func roleassignmentStub(namespace *corev1.Namespace) *orcv1alpha1.RoleAssignment { + obj := &orcv1alpha1.RoleAssignment{} + obj.Name = roleassignmentName + obj.Namespace = namespace.Name + return obj +} + +func testRoleAssignmentResource() *applyconfigv1alpha1.RoleAssignmentResourceSpecApplyConfiguration { + return applyconfigv1alpha1.RoleAssignmentResourceSpec(). + WithRoleRef("role"). + WithUserRef("user"). + WithProjectRef("project") +} + +func baseRoleAssignmentPatch(obj client.Object) *applyconfigv1alpha1.RoleAssignmentApplyConfiguration { + return applyconfigv1alpha1.RoleAssignment(obj.GetName(), obj.GetNamespace()). + WithSpec(applyconfigv1alpha1.RoleAssignmentSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testRoleAssignmentImport() *applyconfigv1alpha1.RoleAssignmentImportApplyConfiguration { + return applyconfigv1alpha1.RoleAssignmentImport(). + WithFilter(applyconfigv1alpha1.RoleAssignmentFilter().WithRoleRef("admin")) +} + +var _ = Describe("ORC RoleAssignment API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.RoleAssignmentApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return roleassignmentStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.RoleAssignmentApplyConfiguration { + return baseRoleAssignmentPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithResource(testRoleAssignmentResource()) + }, + applyImport: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithImport(testRoleAssignmentImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RoleAssignmentImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RoleAssignmentImport().WithFilter(applyconfigv1alpha1.RoleAssignmentFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RoleAssignmentImport().WithFilter(applyconfigv1alpha1.RoleAssignmentFilter().WithRoleRef("admin"))) + }, + applyManaged: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.RoleAssignmentApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.RoleAssignment).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.RoleAssignment).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a roleassignment without required fields", func(ctx context.Context) { + obj := roleassignmentStub(namespace) + patch := baseRoleAssignmentPatch(obj) + patch.Spec.WithResource(applyconfigv1alpha1.RoleAssignmentResourceSpec()) + Expect(applyObj(ctx, obj, patch)).NotTo(Succeed()) + }) + + It("should have immutable RoleAssignmentResourceSpec", func(ctx context.Context) { + obj := roleassignmentStub(namespace) + patch := baseRoleAssignmentPatch(obj) + patch.Spec.WithResource(applyconfigv1alpha1.RoleAssignmentResourceSpec(). + WithRoleRef("role"). + WithUserRef("user"). + WithProjectRef("project")) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + + // Try to change any field - should fail because entire spec is immutable + patch.Spec.WithResource(applyconfigv1alpha1.RoleAssignmentResourceSpec(). + WithRoleRef("role"). + WithUserRef("user-changed"). + WithProjectRef("project")) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("RoleAssignmentResourceSpec is immutable"))) + }) + + // TODO(scaffolding): Add more resource-specific validation tests. + // Some common things to test: + // - Immutability of fields with `self == oldSelf` validation + // - Enum validation (valid and invalid values) + // - Numeric range validation (min/max bounds) + // - Tag uniqueness (if the resource has tags with listType=set) + // - Format validation (CIDR, UUID, etc.) + // - Cross-field validation rules +}) diff --git a/test/apivalidations/router_test.go b/test/apivalidations/router_test.go new file mode 100644 index 000000000..f574b8afa --- /dev/null +++ b/test/apivalidations/router_test.go @@ -0,0 +1,143 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + routerObjName = "router" + routerID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae132" +) + +func routerStub(namespace *corev1.Namespace) *orcv1alpha1.Router { + obj := &orcv1alpha1.Router{} + obj.Name = routerObjName + obj.Namespace = namespace.Name + return obj +} + +func testRouterResource() *applyconfigv1alpha1.RouterResourceSpecApplyConfiguration { + return applyconfigv1alpha1.RouterResourceSpec() +} + +func baseRouterPatch(router client.Object) *applyconfigv1alpha1.RouterApplyConfiguration { + return applyconfigv1alpha1.Router(router.GetName(), router.GetNamespace()). + WithSpec(applyconfigv1alpha1.RouterSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testRouterImport() *applyconfigv1alpha1.RouterImportApplyConfiguration { + return applyconfigv1alpha1.RouterImport().WithID(routerID) +} + +var _ = Describe("ORC Router API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.RouterApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return routerStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.RouterApplyConfiguration { + return baseRouterPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithResource(testRouterResource()) + }, + applyImport: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithImport(testRouterImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RouterImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RouterImport().WithFilter(applyconfigv1alpha1.RouterFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RouterImport().WithFilter(applyconfigv1alpha1.RouterFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.RouterApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Router).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Router).Spec.ManagedOptions.OnDelete + }, + }) + + It("should have immutable externalGateways", func(ctx context.Context) { + router := routerStub(namespace) + patch := baseRouterPatch(router) + patch.Spec.WithResource(applyconfigv1alpha1.RouterResourceSpec(). + WithExternalGateways(applyconfigv1alpha1.ExternalGateway().WithNetworkRef("net-a"))) + Expect(applyObj(ctx, router, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.RouterResourceSpec(). + WithExternalGateways(applyconfigv1alpha1.ExternalGateway().WithNetworkRef("net-b"))) + Expect(applyObj(ctx, router, patch)).To(MatchError(ContainSubstring("externalGateways is immutable"))) + }) + + It("should have immutable distributed", func(ctx context.Context) { + router := routerStub(namespace) + patch := baseRouterPatch(router) + patch.Spec.WithResource(applyconfigv1alpha1.RouterResourceSpec(). + WithDistributed(true)) + Expect(applyObj(ctx, router, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.RouterResourceSpec(). + WithDistributed(false)) + Expect(applyObj(ctx, router, patch)).To(MatchError(ContainSubstring("distributed is immutable"))) + }) + + It("should have immutable projectRef", func(ctx context.Context) { + router := routerStub(namespace) + patch := baseRouterPatch(router) + patch.Spec.WithResource(applyconfigv1alpha1.RouterResourceSpec(). + WithProjectRef("project-a")) + Expect(applyObj(ctx, router, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.RouterResourceSpec(). + WithProjectRef("project-b")) + Expect(applyObj(ctx, router, patch)).To(MatchError(ContainSubstring("projectRef is immutable"))) + }) + + It("should reject duplicate tags", func(ctx context.Context) { + router := routerStub(namespace) + patch := baseRouterPatch(router) + patch.Spec.WithResource(applyconfigv1alpha1.RouterResourceSpec(). + WithTags("foo", "bar", "foo")) + Expect(applyObj(ctx, router, patch)).NotTo(Succeed()) + }) +}) diff --git a/test/apivalidations/routerinterface_test.go b/test/apivalidations/routerinterface_test.go new file mode 100644 index 000000000..efcad5eed --- /dev/null +++ b/test/apivalidations/routerinterface_test.go @@ -0,0 +1,133 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + routerInterfaceName = "routerinterface" +) + +func routerInterfaceStub(namespace *corev1.Namespace) *orcv1alpha1.RouterInterface { + obj := &orcv1alpha1.RouterInterface{} + obj.Name = routerInterfaceName + obj.Namespace = namespace.Name + return obj +} + +func baseRouterInterfacePatch(ri client.Object) *applyconfigv1alpha1.RouterInterfaceApplyConfiguration { + return applyconfigv1alpha1.RouterInterface(ri.GetName(), ri.GetNamespace()) +} + +var _ = Describe("ORC RouterInterface API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + It("should allow to create a valid router interface", func(ctx context.Context) { + ri := routerInterfaceStub(namespace) + patch := baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType(orcv1alpha1.RouterInterfaceTypeSubnet). + WithRouterRef("my-router"). + WithSubnetRef("my-subnet")) + Expect(applyObj(ctx, ri, patch)).To(Succeed()) + }) + + It("should reject missing required field type", func(ctx context.Context) { + ri := routerInterfaceStub(namespace) + patch := baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithRouterRef("my-router"). + WithSubnetRef("my-subnet")) + Expect(applyObj(ctx, ri, patch)).To(MatchError(ContainSubstring("spec.type"))) + }) + + It("should reject missing required field routerRef", func(ctx context.Context) { + ri := routerInterfaceStub(namespace) + patch := baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType(orcv1alpha1.RouterInterfaceTypeSubnet). + WithSubnetRef("my-subnet")) + Expect(applyObj(ctx, ri, patch)).To(MatchError(ContainSubstring("spec.routerRef"))) + }) + + It("should reject invalid type enum value", func(ctx context.Context) { + ri := routerInterfaceStub(namespace) + patch := baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType("Invalid"). + WithRouterRef("my-router"). + WithSubnetRef("my-subnet")) + Expect(applyObj(ctx, ri, patch)).NotTo(Succeed()) + }) + + It("should require subnetRef when type is Subnet", func(ctx context.Context) { + ri := routerInterfaceStub(namespace) + patch := baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType(orcv1alpha1.RouterInterfaceTypeSubnet). + WithRouterRef("my-router")) + Expect(applyObj(ctx, ri, patch)).To(MatchError(ContainSubstring("subnetRef is required when type is 'Subnet'"))) + }) + + It("should keep identity fields immutable", func(ctx context.Context) { + ri := routerInterfaceStub(namespace) + patch := baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType(orcv1alpha1.RouterInterfaceTypeSubnet). + WithRouterRef("router-a"). + WithSubnetRef("subnet-a"). + WithResyncPeriod(metav1.Duration{Duration: 10 * time.Minute})) + Expect(applyObj(ctx, ri, patch)).To(Succeed()) + + patch = baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType(orcv1alpha1.RouterInterfaceTypeSubnet). + WithRouterRef("router-b"). + WithSubnetRef("subnet-a")) + Expect(applyObj(ctx, ri, patch)).To(MatchError(ContainSubstring("routerRef is immutable"))) + + patch = baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType(orcv1alpha1.RouterInterfaceTypeSubnet). + WithRouterRef("router-a"). + WithSubnetRef("subnet-b")) + Expect(applyObj(ctx, ri, patch)).To(MatchError(ContainSubstring("subnetRef is immutable"))) + + patch = baseRouterInterfacePatch(ri) + patch.WithSpec(applyconfigv1alpha1.RouterInterfaceSpec(). + WithType(orcv1alpha1.RouterInterfaceTypeSubnet). + WithRouterRef("router-a"). + WithSubnetRef("subnet-a"). + WithResyncPeriod(metav1.Duration{Duration: time.Hour})) + Expect(applyObj(ctx, ri, patch)).To(Succeed()) + }) +}) diff --git a/test/apivalidations/securitygroup_test.go b/test/apivalidations/securitygroup_test.go index 732c5493c..d55ce6560 100644 --- a/test/apivalidations/securitygroup_test.go +++ b/test/apivalidations/securitygroup_test.go @@ -65,104 +65,41 @@ var _ = Describe("ORC SecurityGroup API validations", func() { namespace = createNamespace() }) - It("should allow to create a minimal security group and managementPolicy should default to managed", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec.WithResource(applyconfigv1alpha1.SecurityGroupResourceSpec()) - Expect(applyObj(ctx, securityGroup, patch)).To(Succeed()) - Expect(securityGroup.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) - }) - - It("should require import for unmanaged", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) - Expect(applyObj(ctx, securityGroup, patch)).NotTo(Succeed()) - - patch.Spec.WithImport(testSecurityGroupImport()) - Expect(applyObj(ctx, securityGroup, patch)).To(Succeed()) - }) - - It("should not permit unmanaged with resource", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(testSecurityGroupImport()). - WithResource(testSecurityGroupResource()) - Expect(applyObj(ctx, securityGroup, patch)).NotTo(Succeed()) - }) - - It("should not permit empty import", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.SecurityGroupImport()) - Expect(applyObj(ctx, securityGroup, patch)).NotTo(Succeed()) - }) - - It("should not permit empty import filter", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.SecurityGroupImport(). - WithFilter(applyconfigv1alpha1.SecurityGroupFilter())) - Expect(applyObj(ctx, securityGroup, patch)).NotTo(Succeed()) - }) - - It("should permit import filter with name", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.SecurityGroupImport(). - WithFilter(applyconfigv1alpha1.SecurityGroupFilter().WithName("foo"))) - Expect(applyObj(ctx, securityGroup, patch)).To(Succeed()) - }) - - It("should require resource for managed", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) - Expect(applyObj(ctx, securityGroup, patch)).NotTo(Succeed()) - - patch.Spec.WithResource(testSecurityGroupResource()) - Expect(applyObj(ctx, securityGroup, patch)).To(Succeed()) - }) - - It("should not permit managed with import", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec. - WithImport(testSecurityGroupImport()). - WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged). - WithResource(testSecurityGroupResource()) - Expect(applyObj(ctx, securityGroup, patch)).NotTo(Succeed()) - }) - - It("should not permit managedOptions for unmanaged", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec. - WithImport(testSecurityGroupImport()). - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithManagedOptions(applyconfigv1alpha1.ManagedOptions(). - WithOnDelete(orcv1alpha1.OnDeleteDetach)) - Expect(applyObj(ctx, securityGroup, patch)).NotTo(Succeed()) - }) - - It("should permit managedOptions for managed", func(ctx context.Context) { - securityGroup := securityGroupStub(namespace) - patch := baseSecurityGroupPatch(securityGroup) - patch.Spec.WithResource(applyconfigv1alpha1.SecurityGroupResourceSpec()) - patch.Spec. - WithManagedOptions(applyconfigv1alpha1.ManagedOptions(). - WithOnDelete(orcv1alpha1.OnDeleteDetach)).WithResource( - applyconfigv1alpha1.SecurityGroupResourceSpec()) - Expect(applyObj(ctx, securityGroup, patch)).To(Succeed()) - Expect(securityGroup.Spec.ManagedOptions.OnDelete).To(Equal(orcv1alpha1.OnDelete("detach"))) + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.SecurityGroupApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return securityGroupStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.SecurityGroupApplyConfiguration { + return baseSecurityGroupPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithResource(testSecurityGroupResource()) + }, + applyImport: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithImport(testSecurityGroupImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.SecurityGroupImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.SecurityGroupImport().WithFilter(applyconfigv1alpha1.SecurityGroupFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.SecurityGroupImport().WithFilter(applyconfigv1alpha1.SecurityGroupFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.SecurityGroupApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.SecurityGroup).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.SecurityGroup).Spec.ManagedOptions.OnDelete + }, }) It("should not permit invalid direction", func(ctx context.Context) { diff --git a/test/apivalidations/server_test.go b/test/apivalidations/server_test.go new file mode 100644 index 000000000..9af650f79 --- /dev/null +++ b/test/apivalidations/server_test.go @@ -0,0 +1,224 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + serverName = "server" + serverID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae134" +) + +func serverStub(namespace *corev1.Namespace) *orcv1alpha1.Server { + obj := &orcv1alpha1.Server{} + obj.Name = serverName + obj.Namespace = namespace.Name + return obj +} + +func testServerResource() *applyconfigv1alpha1.ServerResourceSpecApplyConfiguration { + return applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")) +} + +func baseServerPatch(server client.Object) *applyconfigv1alpha1.ServerApplyConfiguration { + return applyconfigv1alpha1.Server(server.GetName(), server.GetNamespace()). + WithSpec(applyconfigv1alpha1.ServerSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testServerImport() *applyconfigv1alpha1.ServerImportApplyConfiguration { + return applyconfigv1alpha1.ServerImport().WithID(serverID) +} + +var _ = Describe("ORC Server API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.ServerApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return serverStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.ServerApplyConfiguration { + return baseServerPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithResource(testServerResource()) + }, + applyImport: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithImport(testServerImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServerImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServerImport().WithFilter(applyconfigv1alpha1.ServerFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServerImport().WithFilter(applyconfigv1alpha1.ServerFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.ServerApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Server).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Server).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a server without required fields", func(ctx context.Context) { + server := serverStub(namespace) + patch := baseServerPatch(server) + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec()) + Expect(applyObj(ctx, server, patch)).NotTo(Succeed()) + + // Missing flavorRef + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port"))) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("spec.resource.flavorRef"))) + + // Missing imageRef or bootVolume + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port"))) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("either imageRef or bootVolume must be specified"))) + + // Missing ports + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor")) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("spec.resource.ports"))) + }) + + It("should have immutable imageRef", func(ctx context.Context) { + server := serverStub(namespace) + patch := baseServerPatch(server) + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("image-a"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port"))) + Expect(applyObj(ctx, server, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("image-b"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port"))) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("imageRef is immutable"))) + }) + + It("should have immutable flavorRef", func(ctx context.Context) { + server := serverStub(namespace) + patch := baseServerPatch(server) + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("flavor-a"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port"))) + Expect(applyObj(ctx, server, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("flavor-b"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port"))) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("flavorRef is immutable"))) + }) + + It("should have immutable schedulerHints", func(ctx context.Context) { + server := serverStub(namespace) + patch := baseServerPatch(server) + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")). + WithSchedulerHints(applyconfigv1alpha1.ServerSchedulerHints().WithServerGroupRef("sg-a"))) + Expect(applyObj(ctx, server, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")). + WithSchedulerHints(applyconfigv1alpha1.ServerSchedulerHints().WithServerGroupRef("sg-b"))) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("schedulerHints is immutable"))) + }) + + It("should have immutable keypairRef", func(ctx context.Context) { + server := serverStub(namespace) + patch := baseServerPatch(server) + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")). + WithKeypairRef("kp-a")) + Expect(applyObj(ctx, server, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")). + WithKeypairRef("kp-b")) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("keypairRef is immutable"))) + }) + + It("should have immutable configDrive", func(ctx context.Context) { + server := serverStub(namespace) + patch := baseServerPatch(server) + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")). + WithConfigDrive(true)) + Expect(applyObj(ctx, server, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")). + WithConfigDrive(false)) + Expect(applyObj(ctx, server, patch)).To(MatchError(ContainSubstring("configDrive is immutable"))) + }) + + It("should reject duplicate tags", func(ctx context.Context) { + server := serverStub(namespace) + patch := baseServerPatch(server) + patch.Spec.WithResource(applyconfigv1alpha1.ServerResourceSpec(). + WithImageRef("my-image"). + WithFlavorRef("my-flavor"). + WithPorts(applyconfigv1alpha1.ServerPortSpec().WithPortRef("my-port")). + WithTags("foo", "bar", "foo")) + Expect(applyObj(ctx, server, patch)).NotTo(Succeed()) + }) +}) diff --git a/test/apivalidations/servergroup_test.go b/test/apivalidations/servergroup_test.go new file mode 100644 index 000000000..1e9252222 --- /dev/null +++ b/test/apivalidations/servergroup_test.go @@ -0,0 +1,157 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + serverGroupName = "servergroup" + serverGroupID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae129" +) + +func serverGroupStub(namespace *corev1.Namespace) *orcv1alpha1.ServerGroup { + obj := &orcv1alpha1.ServerGroup{} + obj.Name = serverGroupName + obj.Namespace = namespace.Name + return obj +} + +func testServerGroupResource() *applyconfigv1alpha1.ServerGroupResourceSpecApplyConfiguration { + return applyconfigv1alpha1.ServerGroupResourceSpec(). + WithPolicy(orcv1alpha1.ServerGroupPolicyAffinity) +} + +func baseServerGroupPatch(serverGroup client.Object) *applyconfigv1alpha1.ServerGroupApplyConfiguration { + return applyconfigv1alpha1.ServerGroup(serverGroup.GetName(), serverGroup.GetNamespace()). + WithSpec(applyconfigv1alpha1.ServerGroupSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testServerGroupImport() *applyconfigv1alpha1.ServerGroupImportApplyConfiguration { + return applyconfigv1alpha1.ServerGroupImport().WithID(serverGroupID) +} + +var _ = Describe("ORC ServerGroup API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.ServerGroupApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return serverGroupStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.ServerGroupApplyConfiguration { + return baseServerGroupPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { + p.Spec.WithResource(testServerGroupResource()) + }, + applyImport: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { p.Spec.WithImport(testServerGroupImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServerGroupImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServerGroupImport().WithFilter(applyconfigv1alpha1.ServerGroupFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServerGroupImport().WithFilter(applyconfigv1alpha1.ServerGroupFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.ServerGroupApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.ServerGroup).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.ServerGroup).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a servergroup without required field policy", func(ctx context.Context) { + serverGroup := serverGroupStub(namespace) + patch := baseServerGroupPatch(serverGroup) + patch.Spec.WithResource(applyconfigv1alpha1.ServerGroupResourceSpec()) + Expect(applyObj(ctx, serverGroup, patch)).To(MatchError(ContainSubstring("spec.resource.policy"))) + }) + + It("should be immutable", func(ctx context.Context) { + serverGroup := serverGroupStub(namespace) + patch := baseServerGroupPatch(serverGroup) + patch.Spec.WithResource(applyconfigv1alpha1.ServerGroupResourceSpec(). + WithPolicy(orcv1alpha1.ServerGroupPolicyAffinity)) + Expect(applyObj(ctx, serverGroup, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.ServerGroupResourceSpec(). + WithPolicy(orcv1alpha1.ServerGroupPolicyAntiAffinity)) + Expect(applyObj(ctx, serverGroup, patch)).To(MatchError(ContainSubstring("ServerGroupResourceSpec is immutable"))) + }) + + It("should reject invalid policy enum value", func(ctx context.Context) { + serverGroup := serverGroupStub(namespace) + patch := baseServerGroupPatch(serverGroup) + patch.Spec.WithResource(applyconfigv1alpha1.ServerGroupResourceSpec(). + WithPolicy("invalid")) + Expect(applyObj(ctx, serverGroup, patch)).NotTo(Succeed()) + }) + + DescribeTable("should permit valid policy enum values", + func(ctx context.Context, policy orcv1alpha1.ServerGroupPolicy) { + serverGroup := serverGroupStub(namespace) + patch := baseServerGroupPatch(serverGroup) + patch.Spec.WithResource(applyconfigv1alpha1.ServerGroupResourceSpec(). + WithPolicy(policy)) + Expect(applyObj(ctx, serverGroup, patch)).To(Succeed()) + }, + Entry(string(orcv1alpha1.ServerGroupPolicyAffinity), orcv1alpha1.ServerGroupPolicyAffinity), + Entry(string(orcv1alpha1.ServerGroupPolicyAntiAffinity), orcv1alpha1.ServerGroupPolicyAntiAffinity), + Entry(string(orcv1alpha1.ServerGroupPolicySoftAffinity), orcv1alpha1.ServerGroupPolicySoftAffinity), + Entry(string(orcv1alpha1.ServerGroupPolicySoftAntiAffinity), orcv1alpha1.ServerGroupPolicySoftAntiAffinity), + ) + + It("should permit maxServerPerHost with anti-affinity policy", func(ctx context.Context) { + serverGroup := serverGroupStub(namespace) + patch := baseServerGroupPatch(serverGroup) + patch.Spec.WithResource(applyconfigv1alpha1.ServerGroupResourceSpec(). + WithPolicy(orcv1alpha1.ServerGroupPolicyAntiAffinity). + WithRules(applyconfigv1alpha1.ServerGroupRules().WithMaxServerPerHost(2))) + Expect(applyObj(ctx, serverGroup, patch)).To(Succeed()) + }) + + It("should reject maxServerPerHost with non-anti-affinity policy", func(ctx context.Context) { + serverGroup := serverGroupStub(namespace) + patch := baseServerGroupPatch(serverGroup) + patch.Spec.WithResource(applyconfigv1alpha1.ServerGroupResourceSpec(). + WithPolicy(orcv1alpha1.ServerGroupPolicyAffinity). + WithRules(applyconfigv1alpha1.ServerGroupRules().WithMaxServerPerHost(2))) + Expect(applyObj(ctx, serverGroup, patch)).To(MatchError(ContainSubstring("maxServerPerHost can only be used with the anti-affinity policy"))) + }) +}) diff --git a/test/apivalidations/service_test.go b/test/apivalidations/service_test.go new file mode 100644 index 000000000..4c6c0ca1a --- /dev/null +++ b/test/apivalidations/service_test.go @@ -0,0 +1,100 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + serviceName = "service" + serviceID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae123" +) + +func serviceStub(namespace *corev1.Namespace) *orcv1alpha1.Service { + obj := &orcv1alpha1.Service{} + obj.Name = serviceName + obj.Namespace = namespace.Name + return obj +} + +func testServiceResource() *applyconfigv1alpha1.ServiceResourceSpecApplyConfiguration { + return applyconfigv1alpha1.ServiceResourceSpec().WithType("compute") +} + +func baseServicePatch(service client.Object) *applyconfigv1alpha1.ServiceApplyConfiguration { + return applyconfigv1alpha1.Service(service.GetName(), service.GetNamespace()). + WithSpec(applyconfigv1alpha1.ServiceSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testServiceImport() *applyconfigv1alpha1.ServiceImportApplyConfiguration { + return applyconfigv1alpha1.ServiceImport().WithID(serviceID) +} + +var _ = Describe("ORC Service API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.ServiceApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return serviceStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.ServiceApplyConfiguration { return baseServicePatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { p.Spec.WithResource(testServiceResource()) }, + applyImport: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { p.Spec.WithImport(testServiceImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServiceImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServiceImport().WithFilter(applyconfigv1alpha1.ServiceFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.ServiceImport().WithFilter(applyconfigv1alpha1.ServiceFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.ServiceApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Service).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Service).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a service without required field type", func(ctx context.Context) { + service := serviceStub(namespace) + patch := baseServicePatch(service) + patch.Spec.WithResource(applyconfigv1alpha1.ServiceResourceSpec()) + Expect(applyObj(ctx, service, patch)).To(MatchError(ContainSubstring("spec.resource.type"))) + }) +}) diff --git a/test/apivalidations/sharenetwork_test.go b/test/apivalidations/sharenetwork_test.go new file mode 100644 index 000000000..e0bd45968 --- /dev/null +++ b/test/apivalidations/sharenetwork_test.go @@ -0,0 +1,124 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + shareNetworkName = "sharenetwork-foo" + shareNetworkID = "7b7a8e4c-1c2d-4e5f-9a8b-3c4d5e6f7a8b" +) + +func shareNetworkStub(namespace *corev1.Namespace) *orcv1alpha1.ShareNetwork { + obj := &orcv1alpha1.ShareNetwork{} + obj.Name = shareNetworkName + obj.Namespace = namespace.Name + return obj +} + +func testShareNetworkResource() *applyconfigv1alpha1.ShareNetworkResourceSpecApplyConfiguration { + return applyconfigv1alpha1.ShareNetworkResourceSpec() +} + +func baseShareNetworkPatch(shareNetwork client.Object) *applyconfigv1alpha1.ShareNetworkApplyConfiguration { + return applyconfigv1alpha1.ShareNetwork(shareNetwork.GetName(), shareNetwork.GetNamespace()). + WithSpec(applyconfigv1alpha1.ShareNetworkSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +var _ = Describe("ORC ShareNetwork API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + It("should allow to create a minimal share network and managementPolicy should default to managed", func(ctx context.Context) { + shareNetwork := shareNetworkStub(namespace) + patch := baseShareNetworkPatch(shareNetwork) + patch.Spec.WithResource(testShareNetworkResource()) + Expect(applyObj(ctx, shareNetwork, patch)).To(Succeed()) + Expect(shareNetwork.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) + }) + + It("should not permit empty import filter", func(ctx context.Context) { + shareNetwork := shareNetworkStub(namespace) + patch := baseShareNetworkPatch(shareNetwork) + patch.Spec. + WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). + WithImport(applyconfigv1alpha1.ShareNetworkImport(). + WithFilter(applyconfigv1alpha1.ShareNetworkFilter())) + Expect(applyObj(ctx, shareNetwork, patch)).NotTo(Succeed()) + }) + + It("should permit valid import filter", func(ctx context.Context) { + shareNetwork := shareNetworkStub(namespace) + patch := baseShareNetworkPatch(shareNetwork) + patch.Spec. + WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). + WithImport(applyconfigv1alpha1.ShareNetworkImport(). + WithFilter(applyconfigv1alpha1.ShareNetworkFilter().WithName("foo").WithDescription("bar"))) + Expect(applyObj(ctx, shareNetwork, patch)).To(Succeed()) + }) + + // NetworkRef and SubnetRef co-dependency validation tests + Describe("networkRef and subnetRef validation", func() { + It("should allow both networkRef and subnetRef together", func(ctx context.Context) { + shareNetwork := shareNetworkStub(namespace) + patch := baseShareNetworkPatch(shareNetwork) + patch.Spec.WithResource( + applyconfigv1alpha1.ShareNetworkResourceSpec(). + WithNetworkRef("foo"). + WithSubnetRef("bar")) + Expect(applyObj(ctx, shareNetwork, patch)).To(Succeed(), "should accept both networkRef and subnetRef") + }) + + It("should allow neither networkRef nor subnetRef", func(ctx context.Context) { + shareNetwork := shareNetworkStub(namespace) + patch := baseShareNetworkPatch(shareNetwork) + patch.Spec.WithResource(testShareNetworkResource()) + Expect(applyObj(ctx, shareNetwork, patch)).To(Succeed(), "should accept when both are absent") + }) + + It("should reject networkRef without subnetRef", func(ctx context.Context) { + shareNetwork := shareNetworkStub(namespace) + patch := baseShareNetworkPatch(shareNetwork) + patch.Spec.WithResource( + applyconfigv1alpha1.ShareNetworkResourceSpec(). + WithNetworkRef("foo")) + Expect(applyObj(ctx, shareNetwork, patch)).NotTo(Succeed(), "should reject networkRef without subnetRef") + }) + + It("should reject subnetRef without networkRef", func(ctx context.Context) { + shareNetwork := shareNetworkStub(namespace) + patch := baseShareNetworkPatch(shareNetwork) + patch.Spec.WithResource( + applyconfigv1alpha1.ShareNetworkResourceSpec(). + WithSubnetRef("bar")) + Expect(applyObj(ctx, shareNetwork, patch)).NotTo(Succeed(), "should reject subnetRef without networkRef") + }) + }) +}) diff --git a/test/apivalidations/subnet_test.go b/test/apivalidations/subnet_test.go index 0177a8852..7915de3c9 100644 --- a/test/apivalidations/subnet_test.go +++ b/test/apivalidations/subnet_test.go @@ -41,6 +41,23 @@ func subnetStub(namespace *corev1.Namespace) *orcv1alpha1.Subnet { return obj } +func testSubnetResource() *applyconfigv1alpha1.SubnetResourceSpecApplyConfiguration { + return applyconfigv1alpha1.SubnetResourceSpec(). + WithNetworkRef(networkName). + WithIPVersion(4). + WithCIDR("192.168.100.0/24") +} + +func testSubnetImport() *applyconfigv1alpha1.SubnetImportApplyConfiguration { + return applyconfigv1alpha1.SubnetImport().WithID(subnetID) +} + +func baseSubnetPatchBase(subnet client.Object) *applyconfigv1alpha1.SubnetApplyConfiguration { + return applyconfigv1alpha1.Subnet(subnet.GetName(), subnet.GetNamespace()). + WithSpec(applyconfigv1alpha1.SubnetSpec(). + WithCloudCredentialsRef(testCredentials())) +} + func baseSubnetPatch(subnet client.Object) *applyconfigv1alpha1.SubnetApplyConfiguration { return applyconfigv1alpha1.Subnet(subnet.GetName(), subnet.GetNamespace()). WithSpec(applyconfigv1alpha1.SubnetSpec(). @@ -57,12 +74,43 @@ var _ = Describe("ORC Subnet API validations", func() { namespace = createNamespace() }) - It("should allow to create a minimal subnet and managementPolicy should default to managed", func(ctx context.Context) { - subnet := subnetStub(namespace) - patch := baseSubnetPatch(subnet) - Expect(applyObj(ctx, subnet, patch)).To(Succeed()) - Expect(subnet.Spec.ManagementPolicy).To(Equal(orcv1alpha1.ManagementPolicyManaged)) + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.SubnetApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return subnetStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.SubnetApplyConfiguration { + return baseSubnetPatchBase(obj) + }, + applyResource: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithResource(testSubnetResource()) + }, + applyImport: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithImport(testSubnetImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.SubnetImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.SubnetImport().WithFilter(applyconfigv1alpha1.SubnetFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.SubnetImport().WithFilter(applyconfigv1alpha1.SubnetFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.SubnetApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Subnet).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Subnet).Spec.ManagedOptions.OnDelete + }, }) + It("should allow valid tags", func(ctx context.Context) { subnet := subnetStub(namespace) patch := baseSubnetPatch(subnet) @@ -203,16 +251,6 @@ var _ = Describe("ORC Subnet API validations", func() { Expect(applyObj(ctx, subnet, patch)).To(Succeed()) }) - It("should not permit empty import filter", func(ctx context.Context) { - subnet := subnetStub(namespace) - patch := baseSubnetPatch(subnet) - patch.Spec. - WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged). - WithImport(applyconfigv1alpha1.SubnetImport(). - WithFilter(applyconfigv1alpha1.SubnetFilter())) - Expect(applyObj(ctx, subnet, patch)).NotTo(Succeed()) - }) - It("should not permit invalid import filter", func(ctx context.Context) { network := subnetStub(namespace) patch := baseSubnetPatch(network) diff --git a/test/apivalidations/suite_test.go b/test/apivalidations/suite_test.go index 595c4a95f..98c037168 100644 --- a/test/apivalidations/suite_test.go +++ b/test/apivalidations/suite_test.go @@ -24,6 +24,8 @@ import ( "testing" "time" + utilrand "k8s.io/apimachinery/pkg/util/rand" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" @@ -147,7 +149,7 @@ var _ = BeforeSuite(func() { func createNamespace() *corev1.Namespace { By("Creating namespace") namespace := corev1.Namespace{} - namespace.GenerateName = "test-" + namespace.Name = "test-" + utilrand.String(10) Expect(k8sClient.Create(ctx, &namespace)).To(Succeed(), "Namespace creation should succeed") DeferCleanup(func() { By("Deleting namespace") diff --git a/test/apivalidations/trunk_test.go b/test/apivalidations/trunk_test.go new file mode 100644 index 000000000..fba896ba9 --- /dev/null +++ b/test/apivalidations/trunk_test.go @@ -0,0 +1,180 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + trunkName = "trunk" + trunkID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae133" +) + +func trunkStub(namespace *corev1.Namespace) *orcv1alpha1.Trunk { + obj := &orcv1alpha1.Trunk{} + obj.Name = trunkName + obj.Namespace = namespace.Name + return obj +} + +func testTrunkResource() *applyconfigv1alpha1.TrunkResourceSpecApplyConfiguration { + return applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("my-port") +} + +func baseTrunkPatch(trunk client.Object) *applyconfigv1alpha1.TrunkApplyConfiguration { + return applyconfigv1alpha1.Trunk(trunk.GetName(), trunk.GetNamespace()). + WithSpec(applyconfigv1alpha1.TrunkSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testTrunkImport() *applyconfigv1alpha1.TrunkImportApplyConfiguration { + return applyconfigv1alpha1.TrunkImport().WithID(trunkID) +} + +var _ = Describe("ORC Trunk API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.TrunkApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return trunkStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.TrunkApplyConfiguration { + return baseTrunkPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithResource(testTrunkResource()) + }, + applyImport: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithImport(testTrunkImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.TrunkImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.TrunkImport().WithFilter(applyconfigv1alpha1.TrunkFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.TrunkImport().WithFilter(applyconfigv1alpha1.TrunkFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.TrunkApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Trunk).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Trunk).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a trunk without required field portRef", func(ctx context.Context) { + trunk := trunkStub(namespace) + patch := baseTrunkPatch(trunk) + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec()) + Expect(applyObj(ctx, trunk, patch)).To(MatchError(ContainSubstring("spec.resource.portRef"))) + }) + + It("should have immutable portRef", func(ctx context.Context) { + trunk := trunkStub(namespace) + patch := baseTrunkPatch(trunk) + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("port-a")) + Expect(applyObj(ctx, trunk, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("port-b")) + Expect(applyObj(ctx, trunk, patch)).To(MatchError(ContainSubstring("portRef is immutable"))) + }) + + It("should have immutable projectRef", func(ctx context.Context) { + trunk := trunkStub(namespace) + patch := baseTrunkPatch(trunk) + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("my-port"). + WithProjectRef("project-a")) + Expect(applyObj(ctx, trunk, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("my-port"). + WithProjectRef("project-b")) + Expect(applyObj(ctx, trunk, patch)).To(MatchError(ContainSubstring("projectRef is immutable"))) + }) + + It("should reject invalid segmentationType enum value in subport", func(ctx context.Context) { + trunk := trunkStub(namespace) + patch := baseTrunkPatch(trunk) + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("my-port"). + WithSubports(applyconfigv1alpha1.TrunkSubportSpec(). + WithPortRef("sub-port"). + WithSegmentationID(100). + WithSegmentationType("invalid"))) + Expect(applyObj(ctx, trunk, patch)).NotTo(Succeed()) + }) + + It("should permit valid segmentationType enum values in subport", func(ctx context.Context) { + trunk := trunkStub(namespace) + patch := baseTrunkPatch(trunk) + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("my-port"). + WithSubports(applyconfigv1alpha1.TrunkSubportSpec(). + WithPortRef("sub-port"). + WithSegmentationID(100). + WithSegmentationType("vlan"))) + Expect(applyObj(ctx, trunk, patch)).To(Succeed()) + }) + + It("should reject segmentationID out of range in subport", func(ctx context.Context) { + trunk := trunkStub(namespace) + patch := baseTrunkPatch(trunk) + + // Below minimum + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("my-port"). + WithSubports(applyconfigv1alpha1.TrunkSubportSpec(). + WithPortRef("sub-port"). + WithSegmentationID(0). + WithSegmentationType("vlan"))) + Expect(applyObj(ctx, trunk, patch)).To(MatchError(ContainSubstring("spec.resource.subports[0].segmentationID"))) + + // Above maximum + patch.Spec.WithResource(applyconfigv1alpha1.TrunkResourceSpec(). + WithPortRef("my-port"). + WithSubports(applyconfigv1alpha1.TrunkSubportSpec(). + WithPortRef("sub-port"). + WithSegmentationID(4095). + WithSegmentationType("vlan"))) + Expect(applyObj(ctx, trunk, patch)).To(MatchError(ContainSubstring("spec.resource.subports[0].segmentationID"))) + }) +}) diff --git a/test/apivalidations/user_test.go b/test/apivalidations/user_test.go new file mode 100644 index 000000000..983c778ab --- /dev/null +++ b/test/apivalidations/user_test.go @@ -0,0 +1,148 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + userName = "user" + userID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae127" +) + +func userStub(namespace *corev1.Namespace) *orcv1alpha1.User { + obj := &orcv1alpha1.User{} + obj.Name = userName + obj.Namespace = namespace.Name + return obj +} + +func testUserResource() *applyconfigv1alpha1.UserResourceSpecApplyConfiguration { + return applyconfigv1alpha1.UserResourceSpec() +} + +func baseUserPatch(user client.Object) *applyconfigv1alpha1.UserApplyConfiguration { + return applyconfigv1alpha1.User(user.GetName(), user.GetNamespace()). + WithSpec(applyconfigv1alpha1.UserSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testUserImport() *applyconfigv1alpha1.UserImportApplyConfiguration { + return applyconfigv1alpha1.UserImport().WithID(userID) +} + +var _ = Describe("ORC User API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.UserApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return userStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.UserApplyConfiguration { return baseUserPatch(obj) }, + applyResource: func(p *applyconfigv1alpha1.UserApplyConfiguration) { p.Spec.WithResource(testUserResource()) }, + applyImport: func(p *applyconfigv1alpha1.UserApplyConfiguration) { p.Spec.WithImport(testUserImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.UserApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.UserImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.UserApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.UserImport().WithFilter(applyconfigv1alpha1.UserFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.UserApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.UserImport().WithFilter(applyconfigv1alpha1.UserFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.UserApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.UserApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.UserApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.User).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.User).Spec.ManagedOptions.OnDelete + }, + }) + + It("should have immutable domainRef", func(ctx context.Context) { + user := userStub(namespace) + patch := baseUserPatch(user) + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithDomainRef("domain-a")) + Expect(applyObj(ctx, user, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithDomainRef("domain-b")) + Expect(applyObj(ctx, user, patch)).To(MatchError(ContainSubstring("domainRef is immutable"))) + }) + + It("should have immutable defaultProjectRef", func(ctx context.Context) { + user := userStub(namespace) + patch := baseUserPatch(user) + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithDefaultProjectRef("project-a")) + Expect(applyObj(ctx, user, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithDefaultProjectRef("project-b")) + Expect(applyObj(ctx, user, patch)).To(MatchError(ContainSubstring("defaultProjectRef is immutable"))) + }) + + It("should allow omitting passwordRef", func(ctx context.Context) { + user := userStub(namespace) + patch := baseUserPatch(user) + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec()) + Expect(applyObj(ctx, user, patch)).To(Succeed()) + }) + + It("should have mutable passwordRef", func(ctx context.Context) { + user := userStub(namespace) + patch := baseUserPatch(user) + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithPasswordRef("password-a")) + Expect(applyObj(ctx, user, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithPasswordRef("password-b")) + Expect(applyObj(ctx, user, patch)).To(Succeed()) + }) + + It("should not allow removing passwordRef once set", func(ctx context.Context) { + user := userStub(namespace) + patch := baseUserPatch(user) + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithPasswordRef("password-a")) + Expect(applyObj(ctx, user, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec(). + WithDescription("updated")) + Expect(applyObj(ctx, user, patch)).To(MatchError(ContainSubstring("passwordRef may not be removed once set"))) + }) +}) diff --git a/test/apivalidations/volume_test.go b/test/apivalidations/volume_test.go new file mode 100644 index 000000000..6bd5bed00 --- /dev/null +++ b/test/apivalidations/volume_test.go @@ -0,0 +1,159 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + volumeName = "volume" + volumeID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae131" +) + +func volumeStub(namespace *corev1.Namespace) *orcv1alpha1.Volume { + obj := &orcv1alpha1.Volume{} + obj.Name = volumeName + obj.Namespace = namespace.Name + return obj +} + +func testVolumeResource() *applyconfigv1alpha1.VolumeResourceSpecApplyConfiguration { + return applyconfigv1alpha1.VolumeResourceSpec().WithSize(1) +} + +func baseVolumePatch(volume client.Object) *applyconfigv1alpha1.VolumeApplyConfiguration { + return applyconfigv1alpha1.Volume(volume.GetName(), volume.GetNamespace()). + WithSpec(applyconfigv1alpha1.VolumeSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testVolumeImport() *applyconfigv1alpha1.VolumeImportApplyConfiguration { + return applyconfigv1alpha1.VolumeImport().WithID(volumeID) +} + +var _ = Describe("ORC Volume API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.VolumeApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return volumeStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.VolumeApplyConfiguration { + return baseVolumePatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithResource(testVolumeResource()) + }, + applyImport: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithImport(testVolumeImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.VolumeImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.VolumeImport().WithFilter(applyconfigv1alpha1.VolumeFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.VolumeImport().WithFilter(applyconfigv1alpha1.VolumeFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.VolumeApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.Volume).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.Volume).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a volume without required field size", func(ctx context.Context) { + volume := volumeStub(namespace) + patch := baseVolumePatch(volume) + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec()) + Expect(applyObj(ctx, volume, patch)).To(MatchError(ContainSubstring("spec.resource.size"))) + }) + + It("should reject size less than minimum", func(ctx context.Context) { + volume := volumeStub(namespace) + patch := baseVolumePatch(volume) + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec().WithSize(0)) + Expect(applyObj(ctx, volume, patch)).To(MatchError(ContainSubstring("spec.resource.size in body should be greater than or equal to 1"))) + }) + + It("should have immutable size", func(ctx context.Context) { + volume := volumeStub(namespace) + patch := baseVolumePatch(volume) + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec().WithSize(1)) + Expect(applyObj(ctx, volume, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec().WithSize(2)) + Expect(applyObj(ctx, volume, patch)).To(MatchError(ContainSubstring("size is immutable"))) + }) + + It("should have immutable volumeTypeRef", func(ctx context.Context) { + volume := volumeStub(namespace) + patch := baseVolumePatch(volume) + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec(). + WithSize(1).WithVolumeTypeRef("type-a")) + Expect(applyObj(ctx, volume, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec(). + WithSize(1).WithVolumeTypeRef("type-b")) + Expect(applyObj(ctx, volume, patch)).To(MatchError(ContainSubstring("volumeTypeRef is immutable"))) + }) + + It("should have immutable availabilityZone", func(ctx context.Context) { + volume := volumeStub(namespace) + patch := baseVolumePatch(volume) + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec(). + WithSize(1).WithAvailabilityZone("az-a")) + Expect(applyObj(ctx, volume, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec(). + WithSize(1).WithAvailabilityZone("az-b")) + Expect(applyObj(ctx, volume, patch)).To(MatchError(ContainSubstring("availabilityZone is immutable"))) + }) + + It("should have immutable imageRef", func(ctx context.Context) { + volume := volumeStub(namespace) + patch := baseVolumePatch(volume) + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec(). + WithSize(1).WithImageRef("image-a")) + Expect(applyObj(ctx, volume, patch)).To(Succeed()) + + patch.Spec.WithResource(applyconfigv1alpha1.VolumeResourceSpec(). + WithSize(1).WithImageRef("image-b")) + Expect(applyObj(ctx, volume, patch)).To(MatchError(ContainSubstring("imageRef is immutable"))) + }) +}) diff --git a/test/apivalidations/volumetype_test.go b/test/apivalidations/volumetype_test.go new file mode 100644 index 000000000..08338b184 --- /dev/null +++ b/test/apivalidations/volumetype_test.go @@ -0,0 +1,106 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + volumeTypeName = "volumetype" + volumeTypeID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae126" +) + +func volumeTypeStub(namespace *corev1.Namespace) *orcv1alpha1.VolumeType { + obj := &orcv1alpha1.VolumeType{} + obj.Name = volumeTypeName + obj.Namespace = namespace.Name + return obj +} + +func testVolumeTypeResource() *applyconfigv1alpha1.VolumeTypeResourceSpecApplyConfiguration { + return applyconfigv1alpha1.VolumeTypeResourceSpec() +} + +func baseVolumeTypePatch(volumeType client.Object) *applyconfigv1alpha1.VolumeTypeApplyConfiguration { + return applyconfigv1alpha1.VolumeType(volumeType.GetName(), volumeType.GetNamespace()). + WithSpec(applyconfigv1alpha1.VolumeTypeSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testVolumeTypeImport() *applyconfigv1alpha1.VolumeTypeImportApplyConfiguration { + return applyconfigv1alpha1.VolumeTypeImport().WithID(volumeTypeID) +} + +var _ = Describe("ORC VolumeType API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.VolumeTypeApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return volumeTypeStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.VolumeTypeApplyConfiguration { + return baseVolumeTypePatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { + p.Spec.WithResource(testVolumeTypeResource()) + }, + applyImport: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { p.Spec.WithImport(testVolumeTypeImport()) }, + applyEmptyImport: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.VolumeTypeImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.VolumeTypeImport().WithFilter(applyconfigv1alpha1.VolumeTypeFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.VolumeTypeImport().WithFilter(applyconfigv1alpha1.VolumeTypeFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.VolumeTypeApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.VolumeType).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.VolumeType).Spec.ManagedOptions.OnDelete + }, + }) + + It("should permit extraSpecs with required fields", func(ctx context.Context) { + volumeType := volumeTypeStub(namespace) + patch := baseVolumeTypePatch(volumeType) + patch.Spec.WithResource(applyconfigv1alpha1.VolumeTypeResourceSpec(). + WithExtraSpecs(applyconfigv1alpha1.VolumeTypeExtraSpec(). + WithName("key").WithValue("value"))) + Expect(applyObj(ctx, volumeType, patch)).To(Succeed()) + }) +}) diff --git a/tools/orc-api-linter/go.mod b/tools/orc-api-linter/go.mod new file mode 100644 index 000000000..6151a1f16 --- /dev/null +++ b/tools/orc-api-linter/go.mod @@ -0,0 +1,18 @@ +module github.com/k-orc/openstack-resource-controller/v2/tools/orc-api-linter + +go 1.24.0 + +require ( + golang.org/x/tools v0.41.0 + sigs.k8s.io/kube-api-linter v0.0.0-20260320123815-c9b9b51b278a +) + +require ( + github.com/golangci/plugin-module-register v0.1.2 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/sync v0.19.0 // indirect + k8s.io/apimachinery v0.32.3 // indirect + k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/tools/orc-api-linter/go.sum b/tools/orc-api-linter/go.sum new file mode 100644 index 000000000..28add0ec5 --- /dev/null +++ b/tools/orc-api-linter/go.sum @@ -0,0 +1,43 @@ +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg= +github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18= +github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= +github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= +k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ= +k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/kube-api-linter v0.0.0-20260320123815-c9b9b51b278a h1:36He06lekH8jv21Z88RiGHRswh/cBoXKfSbFleF7ukM= +sigs.k8s.io/kube-api-linter v0.0.0-20260320123815-c9b9b51b278a/go.mod h1:5mP60UakkCye+eOcZ5p98VnV2O49qreW1gq9TdsUf7Q= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/tools/orc-api-linter/pkg/analysis/noopenstackidref/analyzer.go b/tools/orc-api-linter/pkg/analysis/noopenstackidref/analyzer.go new file mode 100644 index 000000000..69a106479 --- /dev/null +++ b/tools/orc-api-linter/pkg/analysis/noopenstackidref/analyzer.go @@ -0,0 +1,216 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package noopenstackidref + +import ( + "go/ast" + "regexp" + "slices" + "strings" + + "golang.org/x/tools/go/analysis" + "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/extractjsontags" + "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/inspector" + "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/markers" + "sigs.k8s.io/kube-api-linter/pkg/analysis/initializer" + "sigs.k8s.io/kube-api-linter/pkg/analysis/registry" +) + +const ( + name = "noopenstackidref" + doc = `Flags OpenStack ID references in spec structs. + +ORC's API design philosophy states that spec fields should only reference +ORC Kubernetes objects, not OpenStack resources directly by UUID. + +Fields ending with 'ID' or 'IDs' (like ProjectID, NetworkIDs) in spec structs should +instead use KubernetesNameRef type with a 'Ref' or 'Refs' suffix (like ProjectRef, NetworkRefs). + +Additionally, fields ending with 'Ref' or 'Refs' must use the KubernetesNameRef type, +not other types like OpenStackName or string. + +See: https://k-orc.cloud/development/api-design/` +) + +// openstackIDPattern matches field names that end with "ID" or "IDs" and are likely +// references to OpenStack resources by UUID. These should instead use +// KubernetesNameRef with a "Ref" or "Refs" suffix to reference ORC objects. +var openstackIDPattern = regexp.MustCompile(`IDs?$`) + +// refPattern matches field names that end with "Ref" or "Refs". +// These fields should use KubernetesNameRef type. +var refPattern = regexp.MustCompile(`Refs?$`) + +// excludedIDPatterns contains field name patterns that end in "ID" or "IDs" but are +// not OpenStack resource references. +var excludedIDPatterns = []string{ + "SegmentationID", // VLAN segmentation ID, not an OpenStack resource +} + +// excludedRefPatterns contains field name patterns that end in "Ref" or "Refs" but +// intentionally use a different type than KubernetesNameRef. +var excludedRefPatterns = []string{ + "CloudCredentialsRef", // References a credentials secret, not an ORC object +} + +// excludedStructs contains struct names that should not be checked even though +// they don't have "Status" in their name. These are typically nested types used +// exclusively within status structs. +var excludedStructs = []string{ + "ServerInterfaceFixedIP", // Used only in ServerInterfaceStatus.FixedIPs +} + +// Analyzer is the analyzer for the noopenstackidref linter. +var Analyzer = &analysis.Analyzer{ + Name: name, + Doc: doc, + Run: run, + Requires: []*analysis.Analyzer{inspector.Analyzer}, +} + +func init() { + registry.DefaultRegistry().RegisterLinter(initializer.NewInitializer( + name, + Analyzer, + false, // not enabled by default - must be explicitly enabled + )) +} + +func run(pass *analysis.Pass) (any, error) { + inspect, ok := pass.ResultOf[inspector.Analyzer].(inspector.Inspector) + if !ok { + return nil, nil + } + + inspect.InspectFieldsIncludingListTypes(func(field *ast.Field, _ extractjsontags.FieldTagInfo, _ markers.Markers, qualifiedFieldName string) { + checkField(pass, field, qualifiedFieldName) + }) + + return nil, nil +} + +func checkField(pass *analysis.Pass, field *ast.Field, qualifiedFieldName string) { + // qualifiedFieldName is in the form "StructName.FieldName" + parts := strings.SplitN(qualifiedFieldName, ".", 2) + if len(parts) != 2 { + return + } + + structName := parts[0] + fieldName := parts[1] + + // Only check spec-related structs, not status structs + if !isSpecStruct(structName) { + return + } + + // Check if field name ends in Ref/Refs but uses wrong type + if refPattern.MatchString(fieldName) { + // Check if field name is in the Ref exclusion list + if slices.Contains(excludedRefPatterns, fieldName) { + return + } + + if !isKubernetesNameRefTypeOrSlice(field.Type) { + pass.Reportf(field.Pos(), + "field %s has Ref suffix but does not use KubernetesNameRef type; "+ + "see https://k-orc.cloud/development/api-design/", + qualifiedFieldName) + } + return + } + + // Check if field name matches OpenStack ID pattern + if !openstackIDPattern.MatchString(fieldName) { + return + } + + // Check if field name is in the exclusion list + if slices.Contains(excludedIDPatterns, fieldName) { + return + } + + // Allow *KubernetesNameRef type (correct type, even if name ends in ID) + if isKubernetesNameRefType(field.Type) { + return + } + + // Generate the suggested Ref/Refs name based on singular/plural + var suggestedRef string + if strings.HasSuffix(fieldName, "IDs") { + suggestedRef = strings.TrimSuffix(fieldName, "IDs") + "Refs" + } else { + suggestedRef = strings.TrimSuffix(fieldName, "ID") + "Ref" + } + + pass.Reportf(field.Pos(), + "field %s references OpenStack resource by ID in spec; "+ + "use *KubernetesNameRef with %s instead; "+ + "see https://k-orc.cloud/development/api-design/", + qualifiedFieldName, suggestedRef) +} + +// isSpecStruct returns true if the struct name indicates it's a spec-related struct +// (where OpenStack ID references should be flagged), not a status struct +// (where OpenStack IDs are expected and valid). +func isSpecStruct(structName string) bool { + // Status structs are allowed to have OpenStack IDs + if strings.HasSuffix(structName, "Status") || + strings.Contains(structName, "Status") { + return false + } + + // Check excluded structs (nested types used only in status contexts) + if slices.Contains(excludedStructs, structName) { + return false + } + + // All other structs should use KubernetesNameRef for references + return true +} + +// isKubernetesNameRefType checks if the expression is KubernetesNameRef or *KubernetesNameRef. +// This is the only acceptable type for fields that might look like ID references. +func isKubernetesNameRefType(expr ast.Expr) bool { + // Check for *KubernetesNameRef + if starExpr, ok := expr.(*ast.StarExpr); ok { + if ident, ok := starExpr.X.(*ast.Ident); ok { + return ident.Name == "KubernetesNameRef" + } + return false + } + + // Check for KubernetesNameRef (non-pointer) + if ident, ok := expr.(*ast.Ident); ok { + return ident.Name == "KubernetesNameRef" + } + + return false +} + +// isKubernetesNameRefTypeOrSlice checks if the expression is KubernetesNameRef, +// *KubernetesNameRef, or []KubernetesNameRef. This is used for Ref/Refs fields +// which may be singular or plural. +func isKubernetesNameRefTypeOrSlice(expr ast.Expr) bool { + // Check for []KubernetesNameRef + if arrayType, ok := expr.(*ast.ArrayType); ok { + return isKubernetesNameRefType(arrayType.Elt) + } + + // Check for KubernetesNameRef or *KubernetesNameRef + return isKubernetesNameRefType(expr) +} diff --git a/tools/orc-api-linter/pkg/analysis/noopenstackidref/analyzer_test.go b/tools/orc-api-linter/pkg/analysis/noopenstackidref/analyzer_test.go new file mode 100644 index 000000000..ba8ee5e79 --- /dev/null +++ b/tools/orc-api-linter/pkg/analysis/noopenstackidref/analyzer_test.go @@ -0,0 +1,28 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package noopenstackidref + +import ( + "testing" + + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestAnalyzer(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, Analyzer, "a") +} diff --git a/tools/orc-api-linter/pkg/analysis/noopenstackidref/doc.go b/tools/orc-api-linter/pkg/analysis/noopenstackidref/doc.go new file mode 100644 index 000000000..6e0938616 --- /dev/null +++ b/tools/orc-api-linter/pkg/analysis/noopenstackidref/doc.go @@ -0,0 +1,57 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package noopenstackidref provides a linter that enforces ORC's API design +// philosophy of referencing ORC Kubernetes objects rather than OpenStack +// resources directly by UUID. +// +// # Overview +// +// ORC (OpenStack Resource Controller) manages OpenStack resources through +// Kubernetes custom resources. The API design philosophy states that spec +// fields should only reference other ORC objects, not OpenStack resources +// directly by UUID. +// +// # What this linter checks +// +// The linter flags fields in spec-related structs that: +// - Have names matching OpenStack resource ID patterns (e.g., ProjectID, NetworkID) +// - Are of type *string +// +// These should instead use *KubernetesNameRef with a 'Ref' suffix. +// +// # Examples +// +// Bad (will be flagged): +// +// type UserResourceSpec struct { +// DefaultProjectID *string `json:"defaultProjectID,omitempty"` +// } +// +// Good (correct pattern): +// +// type UserResourceSpec struct { +// DefaultProjectRef *KubernetesNameRef `json:"defaultProjectRef,omitempty"` +// } +// +// # Status structs are exempt +// +// Fields in status structs (ending with 'Status' or 'ResourceStatus') are +// allowed to have OpenStack IDs, as they report what OpenStack returned. +// +// See https://k-orc.cloud/development/architecture/#api-design-philosophy +// for more details on ORC's API design philosophy. +package noopenstackidref diff --git a/tools/orc-api-linter/pkg/analysis/noopenstackidref/testdata/src/a/a.go b/tools/orc-api-linter/pkg/analysis/noopenstackidref/testdata/src/a/a.go new file mode 100644 index 000000000..7d787400f --- /dev/null +++ b/tools/orc-api-linter/pkg/analysis/noopenstackidref/testdata/src/a/a.go @@ -0,0 +1,187 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package a + +// KubernetesNameRef is a reference to a Kubernetes object by name. +type KubernetesNameRef string + +// HostID is a custom struct type (simulating ORC's HostID pattern). +// The bare ID field inside is flagged and requires a nolint comment if intentional. +type HostID struct { + ID string `json:"id,omitempty"` // want `field HostID.ID references OpenStack resource by ID in spec` + ServerRef KubernetesNameRef `json:"serverRef,omitempty"` +} + +// ---- Spec structs: OpenStack IDs should be flagged ---- + +// UserResourceSpec is a spec struct that should be checked. +type UserResourceSpec struct { + // Name is fine, not an OpenStack ID reference. + Name *string `json:"name,omitempty"` + + DefaultProjectID *string `json:"defaultProjectID,omitempty"` // want `field UserResourceSpec.DefaultProjectID references OpenStack resource by ID in spec` + + // DomainRef is good - uses KubernetesNameRef. + DomainRef *KubernetesNameRef `json:"domainRef,omitempty"` +} + +// PortResourceSpec has multiple violations. +type PortResourceSpec struct { + NetworkID *string `json:"networkID,omitempty"` // want `field PortResourceSpec.NetworkID references OpenStack resource by ID in spec` + + SubnetID *string `json:"subnetID,omitempty"` // want `field PortResourceSpec.SubnetID references OpenStack resource by ID in spec` + + // ProjectRef is correct. + ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"` +} + +// ServerSpec tests shortened Spec suffix. +type ServerSpec struct { + ImageID *string `json:"imageID,omitempty"` // want `field ServerSpec.ImageID references OpenStack resource by ID in spec` + + FlavorID *string `json:"flavorID,omitempty"` // want `field ServerSpec.FlavorID references OpenStack resource by ID in spec` +} + +// ---- Filter structs: OpenStack IDs should also be flagged ---- + +// NetworkFilter is a filter struct that should be checked. +type NetworkFilter struct { + ProjectID *string `json:"projectID,omitempty"` // want `field NetworkFilter.ProjectID references OpenStack resource by ID in spec` + + // Name is fine. + Name *string `json:"name,omitempty"` +} + +// ---- Status structs: OpenStack IDs are allowed ---- + +// UserResourceStatus is a status struct where OpenStack IDs are expected. +type UserResourceStatus struct { + // DefaultProjectID is allowed in status - it reports what OpenStack returned. + DefaultProjectID string `json:"defaultProjectID,omitempty"` + + // DomainID is allowed in status. + DomainID string `json:"domainID,omitempty"` +} + +// PortStatus tests shortened Status suffix. +type PortStatus struct { + // NetworkID is allowed in status. + NetworkID string `json:"networkID,omitempty"` +} + +// ---- Nested types used in specs: should also be flagged ---- + +// ServerBlockDevice is a nested type used in ServerResourceSpec. +type ServerBlockDevice struct { + VolumeID *string `json:"volumeID,omitempty"` // want `field ServerBlockDevice.VolumeID references OpenStack resource by ID in spec` + + // Device is fine. + Device *string `json:"device,omitempty"` +} + +// SecurityGroupRule is a nested type. +type SecurityGroupRule struct { + RemoteGroupID *string `json:"remoteGroupID,omitempty"` // want `field SecurityGroupRule.RemoteGroupID references OpenStack resource by ID in spec` +} + +// ---- Edge cases ---- + +// NonPointerIDSpec has non-pointer ID fields which should also be flagged. +type NonPointerIDSpec struct { + ProjectID string `json:"projectID,omitempty"` // want `field NonPointerIDSpec.ProjectID references OpenStack resource by ID in spec` +} + +// UnrelatedIDStruct has ID fields that don't look like OpenStack resources, +// but they are still flagged because any *ID pattern could be a reference. +// Users should add //nolint:noopenstackidref if these are intentional. +type UnrelatedIDStruct struct { + ExternalID *string `json:"externalID,omitempty"` // want `field UnrelatedIDStruct.ExternalID references OpenStack resource by ID in spec` +} + +// StructTypeIDSpec tests that struct-typed ID fields are also flagged. +type StructTypeIDSpec struct { + HostID *HostID `json:"hostID,omitempty"` // want `field StructTypeIDSpec.HostID references OpenStack resource by ID in spec` +} + +// BareIDSpec tests that bare "ID" field is also flagged. +// Use //nolint:noopenstackidref for legitimate cases like spec.import.id. +type BareIDSpec struct { + ID *string `json:"id,omitempty"` // want `field BareIDSpec.ID references OpenStack resource by ID in spec` +} + +// WrongNameCorrectTypeSpec tests that *KubernetesNameRef with wrong name is allowed. +// This is acceptable because the type is correct even if naming is unconventional. +type WrongNameCorrectTypeSpec struct { + // ProjectID with *KubernetesNameRef type is allowed (type takes precedence). + ProjectID *KubernetesNameRef `json:"projectID,omitempty"` +} + +// ---- Plural ID fields: should also be flagged ---- + +// PluralIDsSpec tests that plural IDs fields are flagged. +type PluralIDsSpec struct { + NetworkIDs []string `json:"networkIDs,omitempty"` // want `field PluralIDsSpec.NetworkIDs references OpenStack resource by ID in spec` + + SubnetIDs []string `json:"subnetIDs,omitempty"` // want `field PluralIDsSpec.SubnetIDs references OpenStack resource by ID in spec` + + // SecurityGroupRefs is correct - uses the Refs suffix. + SecurityGroupRefs []KubernetesNameRef `json:"securityGroupRefs,omitempty"` +} + +// PluralIDsStatus tests that plural IDs in status are allowed. +type PluralIDsStatus struct { + // NetworkIDs is allowed in status. + NetworkIDs []string `json:"networkIDs,omitempty"` +} + +// ---- Ref/Refs fields with wrong type: should be flagged ---- + +// OpenStackName simulates the ORC OpenStackName type (wrong type for Refs). +type OpenStackName string + +// WrongTypeRefSpec tests that Ref fields with wrong type are flagged. +type WrongTypeRefSpec struct { + // ProjectRef with *string type is wrong - should use *KubernetesNameRef. + ProjectRef *string `json:"projectRef,omitempty"` // want `field WrongTypeRefSpec.ProjectRef has Ref suffix but does not use KubernetesNameRef type` + + // NetworkRef with OpenStackName type is wrong - should use KubernetesNameRef. + NetworkRef OpenStackName `json:"networkRef,omitempty"` // want `field WrongTypeRefSpec.NetworkRef has Ref suffix but does not use KubernetesNameRef type` + + // SubnetRef is correct - uses KubernetesNameRef. + SubnetRef KubernetesNameRef `json:"subnetRef,omitempty"` + + // RouterRef is correct - uses *KubernetesNameRef. + RouterRef *KubernetesNameRef `json:"routerRef,omitempty"` +} + +// WrongTypeRefsSpec tests that plural Refs fields with wrong type are flagged. +type WrongTypeRefsSpec struct { + // SecurityGroupRefs with []OpenStackName type is wrong - should use []KubernetesNameRef. + SecurityGroupRefs []OpenStackName `json:"securityGroupRefs,omitempty"` // want `field WrongTypeRefsSpec.SecurityGroupRefs has Ref suffix but does not use KubernetesNameRef type` + + // NetworkRefs with []string type is wrong - should use []KubernetesNameRef. + NetworkRefs []string `json:"networkRefs,omitempty"` // want `field WrongTypeRefsSpec.NetworkRefs has Ref suffix but does not use KubernetesNameRef type` + + // SubnetRefs is correct - uses []KubernetesNameRef. + SubnetRefs []KubernetesNameRef `json:"subnetRefs,omitempty"` +} + +// WrongTypeRefsStatus tests that Refs in status with wrong type are allowed. +type WrongTypeRefsStatus struct { + // SecurityGroupRefs is allowed in status even with wrong type. + SecurityGroupRefs []OpenStackName `json:"securityGroupRefs,omitempty"` +} diff --git a/tools/orc-api-linter/plugin.go b/tools/orc-api-linter/plugin.go new file mode 100644 index 000000000..d7d0e22bb --- /dev/null +++ b/tools/orc-api-linter/plugin.go @@ -0,0 +1,40 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package orcapilinter is a golangci-lint plugin that extends kube-api-linter +// with ORC-specific API design rules. +// +// It imports the base kube-api-linter plugin and registers additional ORC-specific +// linters with the registry. This allows all linters to be configured through +// the kubeapilinter section in .golangci.yml. +package orcapilinter + +import ( + pluginbase "sigs.k8s.io/kube-api-linter/pkg/plugin/base" + + // Import the default kube-api-linter linters. + _ "sigs.k8s.io/kube-api-linter/pkg/registration" + + // Import ORC-specific linters to register them with the registry. + _ "github.com/k-orc/openstack-resource-controller/v2/tools/orc-api-linter/pkg/analysis/noopenstackidref" +) + +// New is the entrypoint for the plugin. +// We use the base kube-api-linter plugin which will include both the standard +// KAL linters and our ORC-specific linters registered via init(). +// +//nolint:gochecknoglobals +var New = pluginbase.New diff --git a/website/Makefile b/website/Makefile index 2c86a223c..9e59454e0 100644 --- a/website/Makefile +++ b/website/Makefile @@ -1,7 +1,7 @@ .PHONY: default default: generated -CRD_REF_DOCS?=github.com/elastic/crd-ref-docs@v0.2.0 +CRD_REF_DOCS?=github.com/elastic/crd-ref-docs@v0.3.0 GOMARKDOC?=github.com/princjef/gomarkdoc/cmd/gomarkdoc@v1.1.0 websitedir := $(dir $(lastword $(MAKEFILE_LIST))) diff --git a/website/docs/changelog.md b/website/docs/changelog.md index 2779a1150..ed9a49857 100644 --- a/website/docs/changelog.md +++ b/website/docs/changelog.md @@ -1,5 +1,67 @@ # Changelog +## v2.6 - June 10, 2026 + +### New features + +- Flavor: Added `id` field for creation + +### Bug fixes + +- Tightened adoption filters across multiple controllers (AddressScope, FloatingIP, Group, Network, Port, Project, Router, SecurityGroup, ServerGroup, Subnet, Trunk, User) to prevent adopting resources that don't fully match the spec +- Fixed terminal error classification: use `IsRetryable` instead of `IsConflict` so non-HTTP gophercloud errors (e.g., client-side validation failures) are no longer retried indefinitely (Fixes [#241](https://github.com/k-orc/openstack-resource-controller/issues/241)) +- Treated Neutron quota-exceeded 409 errors as retryable so controllers retry when quota becomes available (Fixes [#667](https://github.com/k-orc/openstack-resource-controller/issues/667)) +- Fixed port status not updating to ACTIVE after server interface attachment +- Fixed volume status not updating to in-use after server attachment + +### Infrastructure improvements + +- Bumped Go to 1.25.11 +- Bumped kuttl to v0.26.0 +- Bumped golang.org/x/net to v0.53.0 and other dependency updates +- Added CI verification for `generate-bundle` + +## v2.5 - April 16, 2026 + +This release adds five new controllers spanning Neutron and Keystone services, +plus significant improvements to existing controllers. This is expected to be +the last v2 release before work begins on v3, which will include minor breaking +API changes. + +### New controllers +- Trunk: Manage Neutron trunk ports +- AddressScope: Manage Neutron address scopes +- Endpoint: Manage Keystone endpoints +- User: Manage Keystone users +- ApplicationCredential: Manage Keystone application credentials + +### New features + +* Port: Added `adminStateUp` and `macAddress` fields +* Port: Added support for port binding +* Server: Added `configdrive` and `metadata` fields +* Volume: Added ability to create bootable volumes from images +* Project: Added ability to specify domainRef +* We now have a process for [lightweight enhancement proposals](https://github.com/k-orc/openstack-resource-controller/tree/main/enhancements). We even got a proposal for [drift detection](https://github.com/k-orc/openstack-resource-controller/blob/main/enhancements/drift-detection.md). + +### Bug fixes + +- SecurityGroup: Fixed inverted error handling for rule creation where retryable errors were marked terminal ([#672](https://github.com/k-orc/openstack-resource-controller/pull/672)) +- SecurityGroup: Fixed availability status by counting security group rules (Fixes [#120](https://github.com/k-orc/openstack-resource-controller/issues/120)) +- RouterInterface: Fixed missing status conditions when routerRef does not exist (Fixes [#314](https://github.com/k-orc/openstack-resource-controller/issues/314)) +- Role: Fixed adoption of domain-scoped roles failing with 409 Conflict ([#733](https://github.com/k-orc/openstack-resource-controller/pull/733)) + +### Infrastructure improvements + +- Go: Bumped to version 1.25.9 +- Bumped dependencies, most notably gophercloud to v2.11.1 +- Added ORC API linter to enforce API design philosophy (no OpenStack IDs in spec fields) +- Added API validation tests for all controllers, with scaffolding support for new controllers +- Added AI agent instructions and skills for assisted development +- CI: Hardened GitHub Actions security (pinned SHAs, scoped permissions, zizmor scanning) +- CI: Added gazpacho, dropped dalmatian testing +* Restored development container image expiration in Quay + ## v2.4 - December 17, 2025 ### New controllers diff --git a/website/docs/crd-reference.md b/website/docs/crd-reference.md index 23b3b2403..3cfdb8ac9 100644 --- a/website/docs/crd-reference.md +++ b/website/docs/crd-reference.md @@ -10,7 +10,10 @@ Package v1alpha1 contains API Schema definitions for the openstack v1alpha1 API ### Resource Types +- [AddressScope](#addressscope) +- [ApplicationCredential](#applicationcredential) - [Domain](#domain) +- [Endpoint](#endpoint) - [Flavor](#flavor) - [FloatingIP](#floatingip) - [Group](#group) @@ -20,13 +23,17 @@ Package v1alpha1 contains API Schema definitions for the openstack v1alpha1 API - [Port](#port) - [Project](#project) - [Role](#role) +- [RoleAssignment](#roleassignment) - [Router](#router) - [RouterInterface](#routerinterface) - [SecurityGroup](#securitygroup) - [Server](#server) - [ServerGroup](#servergroup) - [Service](#service) +- [ShareNetwork](#sharenetwork) - [Subnet](#subnet) +- [Trunk](#trunk) +- [User](#user) - [Volume](#volume) - [VolumeType](#volumetype) @@ -45,8 +52,145 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `ip` _[IPvAny](#ipvany)_ | ip contains a fixed IP address assigned to the port. It must belong
to the referenced subnet's CIDR. If not specified, OpenStack
allocates an available IP from the referenced subnet. | | MaxLength: 45
MinLength: 1
| -| `subnetRef` _[KubernetesNameRef](#kubernetesnameref)_ | subnetRef references the subnet from which to allocate the IP
address. | | MaxLength: 253
MinLength: 1
| +| `ip` _[IPvAny](#ipvany)_ | ip contains a fixed IP address assigned to the port. It must belong
to the referenced subnet's CIDR. If not specified, OpenStack
allocates an available IP from the referenced subnet. | | MaxLength: 45
MinLength: 1
Optional: \{\}
| +| `subnetRef` _[KubernetesNameRef](#kubernetesnameref)_ | subnetRef references the subnet from which to allocate the IP
address. | | MaxLength: 253
MinLength: 1
Required: \{\}
| + + +#### AddressScope + + + +AddressScope is the Schema for an ORC resource. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `AddressScope` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[AddressScopeSpec](#addressscopespec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[AddressScopeStatus](#addressscopestatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### AddressScopeFilter + + + +AddressScopeFilter defines an existing resource by its properties + +_Validation:_ +- MinProperties: 1 + +_Appears in:_ +- [AddressScopeImport](#addressscopeimport) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `ipVersion` _[IPVersion](#ipversion)_ | ipVersion is the IP protocol version. | | Enum: [4 6]
Optional: \{\}
| +| `shared` _boolean_ | shared indicates whether this resource is shared across all
projects or not. By default, only admin users can change set
this value. | | Optional: \{\}
| + + +#### AddressScopeImport + + + +AddressScopeImport specifies an existing resource which will be imported instead of +creating a new one + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [AddressScopeSpec](#addressscopespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[AddressScopeFilter](#addressscopefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| + + +#### AddressScopeResourceSpec + + + +AddressScopeResourceSpec contains the desired state of the resource. + + + +_Appears in:_ +- [AddressScopeSpec](#addressscopespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `ipVersion` _[IPVersion](#ipversion)_ | ipVersion is the IP protocol version. | | Enum: [4 6]
Required: \{\}
| +| `shared` _boolean_ | shared indicates whether this resource is shared across all
projects or not. By default, only admin users can change set
this value. We can't unshared a shared address scope; Neutron
enforces this. | | Optional: \{\}
| + + +#### AddressScopeResourceStatus + + + +AddressScopeResourceStatus represents the observed state of the resource. + + + +_Appears in:_ +- [AddressScopeStatus](#addressscopestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the ID of the Project to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| +| `ipVersion` _integer_ | ipVersion is the IP protocol version. | | Optional: \{\}
| +| `shared` _boolean_ | shared indicates whether this resource is shared across all
projects or not. By default, only admin users can change set
this value. | | Optional: \{\}
| + + +#### AddressScopeSpec + + + +AddressScopeSpec defines the desired state of an ORC object. + + + +_Appears in:_ +- [AddressScope](#addressscope) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `import` _[AddressScopeImport](#addressscopeimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[AddressScopeResourceSpec](#addressscoperesourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| + + +#### AddressScopeStatus + + + +AddressScopeStatus defines the observed state of an ORC resource. + + + +_Appears in:_ +- [AddressScope](#addressscope) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[AddressScopeResourceStatus](#addressscoperesourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### AllocationPool @@ -62,8 +206,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `start` _[IPvAny](#ipvany)_ | start is the first IP address in the allocation pool. | | MaxLength: 45
MinLength: 1
| -| `end` _[IPvAny](#ipvany)_ | end is the last IP address in the allocation pool. | | MaxLength: 45
MinLength: 1
| +| `start` _[IPvAny](#ipvany)_ | start is the first IP address in the allocation pool. | | MaxLength: 45
MinLength: 1
Required: \{\}
| +| `end` _[IPvAny](#ipvany)_ | end is the last IP address in the allocation pool. | | MaxLength: 45
MinLength: 1
Required: \{\}
| #### AllocationPoolStatus @@ -79,8 +223,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `start` _string_ | start is the first IP address in the allocation pool. | | MaxLength: 1024
| -| `end` _string_ | end is the last IP address in the allocation pool. | | MaxLength: 1024
| +| `start` _string_ | start is the first IP address in the allocation pool. | | MaxLength: 1024
Optional: \{\}
| +| `end` _string_ | end is the last IP address in the allocation pool. | | MaxLength: 1024
Optional: \{\}
| #### AllowedAddressPair @@ -96,8 +240,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `ip` _[IPvAny](#ipvany)_ | ip contains an IP address which a server connected to the port can
send packets with. It can be an IP Address or a CIDR (if supported
by the underlying extension plugin). | | MaxLength: 45
MinLength: 1
| -| `mac` _[MAC](#mac)_ | mac contains a MAC address which a server connected to the port can
send packets with. Defaults to the MAC address of the port. | | MaxLength: 17
MinLength: 1
| +| `ip` _[IPvAny](#ipvany)_ | ip contains an IP address which a server connected to the port can
send packets with. It can be an IP Address or a CIDR (if supported
by the underlying extension plugin). | | MaxLength: 45
MinLength: 1
Required: \{\}
| +| `mac` _[MAC](#mac)_ | mac contains a MAC address which a server connected to the port can
send packets with. Defaults to the MAC address of the port. | | MaxLength: 17
MinLength: 1
Optional: \{\}
| #### AllowedAddressPairStatus @@ -113,8 +257,207 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `ip` _string_ | ip contains an IP address which a server connected to the port can
send packets with. | | MaxLength: 1024
| -| `mac` _string_ | mac contains a MAC address which a server connected to the port can
send packets with. | | MaxLength: 1024
| +| `ip` _string_ | ip contains an IP address which a server connected to the port can
send packets with. | | MaxLength: 1024
Optional: \{\}
| +| `mac` _string_ | mac contains a MAC address which a server connected to the port can
send packets with. | | MaxLength: 1024
Optional: \{\}
| + + +#### ApplicationCredential + + + +ApplicationCredential is the Schema for an ORC resource. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `ApplicationCredential` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[ApplicationCredentialSpec](#applicationcredentialspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[ApplicationCredentialStatus](#applicationcredentialstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### ApplicationCredentialAccessRule + + + +ApplicationCredentialAccessRule defines an access rule + +_Validation:_ +- MinProperties: 1 + +_Appears in:_ +- [ApplicationCredentialResourceSpec](#applicationcredentialresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `path` _string_ | path that the application credential is permitted to access | | MaxLength: 1024
Optional: \{\}
| +| `method` _[HTTPMethod](#httpmethod)_ | method that the application credential is permitted to use for a given API endpoint | | Enum: [CONNECT DELETE GET HEAD OPTIONS PATCH POST PUT TRACE]
Optional: \{\}
| +| `serviceRef` _[KubernetesNameRef](#kubernetesnameref)_ | serviceRef identifier for the service that the application credential is permitted to access | | MaxLength: 253
MinLength: 1
Optional: \{\}
| + + +#### ApplicationCredentialAccessRuleStatus + + + + + + + +_Appears in:_ +- [ApplicationCredentialResourceStatus](#applicationcredentialresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id is the ID of this access rule | | MaxLength: 1024
Optional: \{\}
| +| `path` _string_ | path that the application credential is permitted to access | | MaxLength: 1024
Optional: \{\}
| +| `method` _string_ | method that the application credential is permitted to use for a given API endpoint | | MaxLength: 32
Optional: \{\}
| +| `service` _string_ | service type identifier for the service that the application credential is permitted to access | | MaxLength: 1024
Optional: \{\}
| + + +#### ApplicationCredentialFilter + + + +ApplicationCredentialFilter defines an existing resource by its properties + +_Validation:_ +- MinProperties: 2 + +_Appears in:_ +- [ApplicationCredentialImport](#applicationcredentialimport) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `userRef` _[KubernetesNameRef](#kubernetesnameref)_ | userRef is a reference to the ORC User which this resource is associated with.
Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description of the existing resource | | MaxLength: 1024
Optional: \{\}
| + + +#### ApplicationCredentialImport + + + +ApplicationCredentialImport specifies an existing resource which will be imported instead of +creating a new one + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [ApplicationCredentialSpec](#applicationcredentialspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[ApplicationCredentialFilter](#applicationcredentialfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 2
Optional: \{\}
| + + +#### ApplicationCredentialResourceSpec + + + +ApplicationCredentialResourceSpec contains the desired state of the resource. + + + +_Appears in:_ +- [ApplicationCredentialSpec](#applicationcredentialspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `userRef` _[KubernetesNameRef](#kubernetesnameref)_ | userRef is a reference to the ORC User which this resource is associated with.
Note: Due to the nature of the OpenStack API, managing application credentials for a user different than the one ORC is authenticated against can be computationally expensive. In the worst case, all application credentials of all users have to be queried. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `unrestricted` _boolean_ | unrestricted is a flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts | | Optional: \{\}
| +| `secretRef` _[KubernetesNameRef](#kubernetesnameref)_ | secretRef is a reference to a Secret containing the application credential secret | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `roleRefs` _[KubernetesNameRef](#kubernetesnameref) array_ | roleRefs may only contain roles that the user has assigned on the project. If not provided, the roles assigned to the application credential will be the same as the roles in the current token. | | MaxItems: 256
MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `accessRules` _[ApplicationCredentialAccessRule](#applicationcredentialaccessrule) array_ | accessRules is a list of fine grained access control rules | | MaxItems: 256
MinProperties: 1
Optional: \{\}
| +| `expiresAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | expiresAt is the time of expiration for the application credential. If unset, the application credential does not expire. | | Optional: \{\}
| + + +#### ApplicationCredentialResourceStatus + + + +ApplicationCredentialResourceStatus represents the observed state of the resource. + + + +_Appears in:_ +- [ApplicationCredentialStatus](#applicationcredentialstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `unrestricted` _boolean_ | unrestricted is a flag indicating whether the application credential may be used for creation or destruction of other application credentials or trusts | | Optional: \{\}
| +| `projectID` _string_ | projectID of the project the application credential was created for and that authentication requests using this application credential will be scoped to. | | MaxLength: 1024
Optional: \{\}
| +| `roles` _[ApplicationCredentialRoleStatus](#applicationcredentialrolestatus) array_ | roles is a list of role objects may only contain roles that the user has assigned on the project | | MaxItems: 64
Optional: \{\}
| +| `expiresAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | expiresAt is the time of expiration for the application credential. If unset, the application credential does not expire. | | Optional: \{\}
| +| `accessRules` _[ApplicationCredentialAccessRuleStatus](#applicationcredentialaccessrulestatus) array_ | accessRules is a list of fine grained access control rules | | MaxItems: 64
Optional: \{\}
| + + +#### ApplicationCredentialRoleStatus + + + + + + + +_Appears in:_ +- [ApplicationCredentialResourceStatus](#applicationcredentialresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name of an existing role | | MaxLength: 1024
Optional: \{\}
| +| `id` _string_ | id is the ID of a role | | MaxLength: 1024
Optional: \{\}
| +| `domainID` _string_ | domainID of the domain of this role | | MaxLength: 1024
Optional: \{\}
| + + +#### ApplicationCredentialSpec + + + +ApplicationCredentialSpec defines the desired state of an ORC object. + + + +_Appears in:_ +- [ApplicationCredential](#applicationcredential) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `import` _[ApplicationCredentialImport](#applicationcredentialimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[ApplicationCredentialResourceSpec](#applicationcredentialresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| + + +#### ApplicationCredentialStatus + + + +ApplicationCredentialStatus defines the observed state of an ORC resource. + + + +_Appears in:_ +- [ApplicationCredential](#applicationcredential) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[ApplicationCredentialResourceStatus](#applicationcredentialresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### AvailabilityZoneHint @@ -147,6 +490,7 @@ _Validation:_ _Appears in:_ - [HostRoute](#hostroute) - [SecurityGroupRule](#securitygrouprule) +- [ServerSchedulerHints](#serverschedulerhints) - [SubnetFilter](#subnetfilter) - [SubnetResourceSpec](#subnetresourcespec) @@ -163,7 +507,10 @@ CloudCredentialsReference is a reference to a secret containing OpenStack creden _Appears in:_ +- [AddressScopeSpec](#addressscopespec) +- [ApplicationCredentialSpec](#applicationcredentialspec) - [DomainSpec](#domainspec) +- [EndpointSpec](#endpointspec) - [FlavorSpec](#flavorspec) - [FloatingIPSpec](#floatingipspec) - [GroupSpec](#groupspec) @@ -172,20 +519,24 @@ _Appears in:_ - [NetworkSpec](#networkspec) - [PortSpec](#portspec) - [ProjectSpec](#projectspec) +- [RoleAssignmentSpec](#roleassignmentspec) - [RoleSpec](#rolespec) - [RouterSpec](#routerspec) - [SecurityGroupSpec](#securitygroupspec) - [ServerGroupSpec](#servergroupspec) - [ServerSpec](#serverspec) - [ServiceSpec](#servicespec) +- [ShareNetworkSpec](#sharenetworkspec) - [SubnetSpec](#subnetspec) +- [TrunkSpec](#trunkspec) +- [UserSpec](#userspec) - [VolumeSpec](#volumespec) - [VolumeTypeSpec](#volumetypespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `secretName` _string_ | secretName is the name of a secret in the same namespace as the resource being provisioned.
The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file.
The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. | | MaxLength: 253
MinLength: 1
| -| `cloudName` _string_ | cloudName specifies the name of the entry in the clouds.yaml file to use. | | MaxLength: 256
MinLength: 1
| +| `secretName` _string_ | secretName is the name of a secret in the same namespace as the resource being provisioned.
The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file.
The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `cloudName` _string_ | cloudName specifies the name of the entry in the clouds.yaml file to use. | | MaxLength: 256
MinLength: 1
Required: \{\}
| #### DNSDomain @@ -218,9 +569,9 @@ Domain is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Domain` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[DomainSpec](#domainspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[DomainStatus](#domainstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[DomainSpec](#domainspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[DomainStatus](#domainstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### DomainFilter @@ -237,8 +588,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
| -| `enabled` _boolean_ | enabled defines whether a domain is enabled or not. Default is true.
Note: Users can only authorize against an enabled domain (and any of its projects). | | | +| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `enabled` _boolean_ | enabled defines whether a domain is enabled or not. Default is true.
Note: Users can only authorize against an enabled domain (and any of its projects). | | Optional: \{\}
| #### DomainImport @@ -257,8 +608,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[DomainFilter](#domainfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[DomainFilter](#domainfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### DomainResourceSpec @@ -274,9 +625,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `enabled` _boolean_ | enabled defines whether a domain is enabled or not. Default is true.
Note: Users can only authorize against an enabled domain (and any of its projects). | | | +| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `enabled` _boolean_ | enabled defines whether a domain is enabled or not. Default is true.
Note: Users can only authorize against an enabled domain (and any of its projects). | | Optional: \{\}
| #### DomainResourceStatus @@ -292,9 +643,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `enabled` _boolean_ | enabled defines whether a domain is enabled or not. Default is true.
Note: Users can only authorize against an enabled domain (and any of its projects). | | | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `enabled` _boolean_ | enabled defines whether a domain is enabled or not. Default is true.
Note: Users can only authorize against an enabled domain (and any of its projects). | | Optional: \{\}
| #### DomainSpec @@ -310,11 +661,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[DomainImport](#domainimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[DomainResourceSpec](#domainresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[DomainImport](#domainimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[DomainResourceSpec](#domainresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### DomainStatus @@ -330,124 +682,264 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[DomainResourceStatus](#domainresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[DomainResourceStatus](#domainresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| -#### Ethertype +#### Endpoint -_Underlying type:_ _string_ +Endpoint is the Schema for an ORC resource. -_Validation:_ -- Enum: [IPv4 IPv6] -_Appears in:_ -- [SecurityGroupRule](#securitygrouprule) -| Field | Description | -| --- | --- | -| `IPv4` | | -| `IPv6` | | -#### ExternalGateway +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `Endpoint` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[EndpointSpec](#endpointspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[EndpointStatus](#endpointstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| +#### EndpointFilter +EndpointFilter defines an existing resource by its properties +_Validation:_ +- MinProperties: 1 _Appears in:_ -- [RouterResourceSpec](#routerresourcespec) +- [EndpointImport](#endpointimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which the external
gateway is on. | | MaxLength: 253
MinLength: 1
| - - -#### ExternalGatewayStatus +| `interface` _string_ | interface of the existing endpoint. | | Enum: [admin internal public]
Optional: \{\}
| +| `serviceRef` _[KubernetesNameRef](#kubernetesnameref)_ | serviceRef is a reference to the ORC Service which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `url` _string_ | url is the URL of the existing endpoint. | | MaxLength: 1024
Optional: \{\}
| +#### EndpointImport +EndpointImport specifies an existing resource which will be imported instead of +creating a new one +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 _Appears in:_ -- [RouterResourceStatus](#routerresourcestatus) +- [EndpointSpec](#endpointspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `networkID` _string_ | networkID is the ID of the network the gateway is on. | | MaxLength: 1024
| - +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[EndpointFilter](#endpointfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### FilterByKeystoneTags +#### EndpointResourceSpec +EndpointResourceSpec contains the desired state of the resource. _Appears in:_ -- [ProjectFilter](#projectfilter) +- [EndpointSpec](#endpointspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `tags` _[KeystoneTag](#keystonetag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[KeystoneTag](#keystonetag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| -| `notTags` _[KeystoneTag](#keystonetag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[KeystoneTag](#keystonetag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `enabled` _boolean_ | enabled indicates whether the endpoint is enabled or not. | | Optional: \{\}
| +| `interface` _string_ | interface indicates the visibility of the endpoint. | | Enum: [admin internal public]
Required: \{\}
| +| `url` _string_ | url is the endpoint URL. | | MaxLength: 1024
Required: \{\}
| +| `serviceRef` _[KubernetesNameRef](#kubernetesnameref)_ | serviceRef is a reference to the ORC Service which this resource is associated with. | | MaxLength: 253
MinLength: 1
Required: \{\}
| -#### FilterByNeutronTags - +#### EndpointResourceStatus +EndpointResourceStatus represents the observed state of the resource. _Appears in:_ -- [FloatingIPFilter](#floatingipfilter) -- [NetworkFilter](#networkfilter) -- [PortFilter](#portfilter) -- [RouterFilter](#routerfilter) -- [SecurityGroupFilter](#securitygroupfilter) -- [SubnetFilter](#subnetfilter) +- [EndpointStatus](#endpointstatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `enabled` _boolean_ | enabled indicates whether the endpoint is enabled or not. | | Optional: \{\}
| +| `interface` _string_ | interface indicates the visibility of the endpoint. | | MaxLength: 128
Optional: \{\}
| +| `url` _string_ | url is the endpoint URL. | | MaxLength: 1024
Optional: \{\}
| +| `serviceID` _string_ | serviceID is the ID of the Service to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| -#### FilterByServerTags - +#### EndpointSpec +EndpointSpec defines the desired state of an ORC object. _Appears in:_ -- [ServerFilter](#serverfilter) +- [Endpoint](#endpoint) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `tags` _[ServerTag](#servertag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| -| `tagsAny` _[ServerTag](#servertag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| -| `notTags` _[ServerTag](#servertag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| -| `notTagsAny` _[ServerTag](#servertag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| +| `import` _[EndpointImport](#endpointimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[EndpointResourceSpec](#endpointresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| -#### FixedIPStatus +#### EndpointStatus + + + +EndpointStatus defines the observed state of an ORC resource. + + + +_Appears in:_ +- [Endpoint](#endpoint) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[EndpointResourceStatus](#endpointresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + +#### Ethertype + +_Underlying type:_ _string_ + + + +_Validation:_ +- Enum: [IPv4 IPv6] + +_Appears in:_ +- [SecurityGroupRule](#securitygrouprule) + +| Field | Description | +| --- | --- | +| `IPv4` | | +| `IPv6` | | + + +#### ExternalGateway + + + + + + + +_Appears in:_ +- [RouterResourceSpec](#routerresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which the external
gateway is on. | | MaxLength: 253
MinLength: 1
Required: \{\}
| + + +#### ExternalGatewayStatus + + + + + + + +_Appears in:_ +- [RouterResourceStatus](#routerresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `networkID` _string_ | networkID is the ID of the network the gateway is on. | | MaxLength: 1024
Optional: \{\}
| + + +#### FilterByKeystoneTags + + + + + + + +_Appears in:_ +- [ProjectFilter](#projectfilter) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `tags` _[KeystoneTag](#keystonetag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[KeystoneTag](#keystonetag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[KeystoneTag](#keystonetag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[KeystoneTag](#keystonetag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| + + +#### FilterByNeutronTags + + + + + + + +_Appears in:_ +- [FloatingIPFilter](#floatingipfilter) +- [NetworkFilter](#networkfilter) +- [PortFilter](#portfilter) +- [RouterFilter](#routerfilter) +- [SecurityGroupFilter](#securitygroupfilter) +- [SubnetFilter](#subnetfilter) +- [TrunkFilter](#trunkfilter) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| + + +#### FilterByServerTags + + + + + + + +_Appears in:_ +- [ServerFilter](#serverfilter) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `tags` _[ServerTag](#servertag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[ServerTag](#servertag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| +| `notTags` _[ServerTag](#servertag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[ServerTag](#servertag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| + + +#### FixedIPStatus @@ -460,8 +952,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `ip` _string_ | ip contains a fixed IP address assigned to the port. | | MaxLength: 1024
| -| `subnetID` _string_ | subnetID is the ID of the subnet this IP is allocated from. | | MaxLength: 1024
| +| `ip` _string_ | ip contains a fixed IP address assigned to the port. | | MaxLength: 1024
Optional: \{\}
| +| `subnetID` _string_ | subnetID is the ID of the subnet this IP is allocated from. | | MaxLength: 1024
Optional: \{\}
| #### Flavor @@ -478,9 +970,43 @@ Flavor is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Flavor` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[FlavorSpec](#flavorspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[FlavorStatus](#flavorstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[FlavorSpec](#flavorspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[FlavorStatus](#flavorstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### FlavorExtraSpec + + + + + + + +_Appears in:_ +- [FlavorResourceSpec](#flavorresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is the name of the extraspec | | MaxLength: 255
Pattern: `^[a-zA-Z0-9-_:. ]+$`
Required: \{\}
| +| `value` _string_ | value is the value of the extraspec | | MaxLength: 255
Required: \{\}
| + + +#### FlavorExtraSpecStatus + + + + + + + +_Appears in:_ +- [FlavorResourceStatus](#flavorresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is the name of the extraspec | | MaxLength: 255
Optional: \{\}
| +| `value` _string_ | value is the value of the extraspec | | MaxLength: 255
Optional: \{\}
| #### FlavorFilter @@ -497,10 +1023,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `ram` _integer_ | ram is the memory of the flavor, measured in MB. | | Minimum: 1
| -| `vcpus` _integer_ | vcpus is the number of vcpus for the flavor. | | Minimum: 1
| -| `disk` _integer_ | disk is the size of the root disk in GiB. | | Minimum: 0
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `ram` _integer_ | ram is the memory of the flavor, measured in MB. | | Minimum: 1
Optional: \{\}
| +| `vcpus` _integer_ | vcpus is the number of vcpus for the flavor. | | Minimum: 1
Optional: \{\}
| +| `disk` _integer_ | disk is the size of the root disk in GiB. | | Minimum: 0
Optional: \{\}
| #### FlavorImport @@ -519,8 +1045,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[FlavorFilter](#flavorfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[FlavorFilter](#flavorfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### FlavorResourceSpec @@ -536,14 +1062,16 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _string_ | description contains a free form description of the flavor. | | MaxLength: 65535
MinLength: 1
| -| `ram` _integer_ | ram is the memory of the flavor, measured in MB. | | Minimum: 1
| -| `vcpus` _integer_ | vcpus is the number of vcpus for the flavor. | | Minimum: 1
| -| `disk` _integer_ | disk is the size of the root disk that will be created in GiB. If 0
the root disk will be set to exactly the size of the image used to
deploy the instance. However, in this case the scheduler cannot
select the compute host based on the virtual image size. Therefore,
0 should only be used for volume booted instances or for testing
purposes. Volume-backed instances can be enforced for flavors with
zero root disk via the
os_compute_api:servers:create:zero_disk_flavor policy rule. | | Minimum: 0
| -| `swap` _integer_ | swap is the size of a dedicated swap disk that will be allocated, in
MiB. If 0 (the default), no dedicated swap disk will be created. | | Minimum: 0
| -| `isPublic` _boolean_ | isPublic flags a flavor as being available to all projects or not. | | | -| `ephemeral` _integer_ | ephemeral is the size of the ephemeral disk that will be created, in GiB.
Ephemeral disks may be written over on server state changes. So should only
be used as a scratch space for applications that are aware of its
limitations. Defaults to 0. | | Minimum: 0
| +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `id` _string_ | id will be the id of the created resource. If not specified, a random
UUID will be generated by OpenStack. | | MaxLength: 255
MinLength: 1
Pattern: `^[a-zA-Z0-9._-]([a-zA-Z0-9. _-]*[a-zA-Z0-9._-])?$`
Optional: \{\}
| +| `description` _string_ | description contains a free form description of the flavor. | | MaxLength: 65535
MinLength: 1
Optional: \{\}
| +| `ram` _integer_ | ram is the memory of the flavor, measured in MB. | | Minimum: 1
Required: \{\}
| +| `vcpus` _integer_ | vcpus is the number of vcpus for the flavor. | | Minimum: 1
Required: \{\}
| +| `disk` _integer_ | disk is the size of the root disk that will be created in GiB. If 0
the root disk will be set to exactly the size of the image used to
deploy the instance. However, in this case the scheduler cannot
select the compute host based on the virtual image size. Therefore,
0 should only be used for volume booted instances or for testing
purposes. Volume-backed instances can be enforced for flavors with
zero root disk via the
os_compute_api:servers:create:zero_disk_flavor policy rule. | | Minimum: 0
Required: \{\}
| +| `swap` _integer_ | swap is the size of a dedicated swap disk that will be allocated, in
MiB. If 0 (the default), no dedicated swap disk will be created. | | Minimum: 0
Optional: \{\}
| +| `extraSpecs` _[FlavorExtraSpec](#flavorextraspec) array_ | extraSpecs is a list of key-value pairs that define extra specifications for the flavor. | | MaxItems: 128
Optional: \{\}
| +| `isPublic` _boolean_ | isPublic flags a flavor as being available to all projects or not. | | Optional: \{\}
| +| `ephemeral` _integer_ | ephemeral is the size of the ephemeral disk that will be created, in GiB.
Ephemeral disks may be written over on server state changes. So should only
be used as a scratch space for applications that are aware of its
limitations. Defaults to 0. | | Minimum: 0
Optional: \{\}
| #### FlavorResourceStatus @@ -559,14 +1087,15 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the flavor. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 65535
| -| `ram` _integer_ | ram is the memory of the flavor, measured in MB. | | | -| `vcpus` _integer_ | vcpus is the number of vcpus for the flavor. | | | -| `disk` _integer_ | disk is the size of the root disk that will be created in GiB. | | | -| `swap` _integer_ | swap is the size of a dedicated swap disk that will be allocated, in
MiB. | | | -| `isPublic` _boolean_ | isPublic flags a flavor as being available to all projects or not. | | | -| `ephemeral` _integer_ | ephemeral is the size of the ephemeral disk, in GiB. | | | +| `name` _string_ | name is a Human-readable name for the flavor. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 65535
Optional: \{\}
| +| `ram` _integer_ | ram is the memory of the flavor, measured in MB. | | Optional: \{\}
| +| `vcpus` _integer_ | vcpus is the number of vcpus for the flavor. | | Optional: \{\}
| +| `disk` _integer_ | disk is the size of the root disk that will be created in GiB. | | Optional: \{\}
| +| `swap` _integer_ | swap is the size of a dedicated swap disk that will be allocated, in
MiB. | | Optional: \{\}
| +| `extraSpecs` _[FlavorExtraSpecStatus](#flavorextraspecstatus) array_ | extraSpecs is a map of key-value pairs that define extra specifications for the flavor. | | MaxItems: 128
Optional: \{\}
| +| `isPublic` _boolean_ | isPublic flags a flavor as being available to all projects or not. | | Optional: \{\}
| +| `ephemeral` _integer_ | ephemeral is the size of the ephemeral disk, in GiB. | | Optional: \{\}
| #### FlavorSpec @@ -582,11 +1111,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[FlavorImport](#flavorimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[FlavorResourceSpec](#flavorresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[FlavorImport](#flavorimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[FlavorResourceSpec](#flavorresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### FlavorStatus @@ -602,9 +1132,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[FlavorResourceStatus](#flavorresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[FlavorResourceStatus](#flavorresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### FloatingIP @@ -621,9 +1152,9 @@ FloatingIP is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `FloatingIP` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[FloatingIPSpec](#floatingipspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[FloatingIPStatus](#floatingipstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[FloatingIPSpec](#floatingipspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[FloatingIPStatus](#floatingipstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### FloatingIPFilter @@ -640,16 +1171,16 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `floatingIP` _[IPvAny](#ipvany)_ | floatingIP is the floatingip address. | | MaxLength: 45
MinLength: 1
| -| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `floatingNetworkRef` _[KubernetesNameRef](#kubernetesnameref)_ | floatingNetworkRef is a reference to the ORC Network which this resource is associated with. | | MaxLength: 253
MinLength: 1
| -| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to the ORC Port which this resource is associated with. | | MaxLength: 253
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| -| `status` _string_ | status is the status of the floatingip. | | MaxLength: 1024
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `floatingIP` _[IPvAny](#ipvany)_ | floatingIP is the floatingip address. | | MaxLength: 45
MinLength: 1
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `floatingNetworkRef` _[KubernetesNameRef](#kubernetesnameref)_ | floatingNetworkRef is a reference to the ORC Network which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to the ORC Port which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `status` _string_ | status is the status of the floatingip. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| #### FloatingIPImport @@ -668,8 +1199,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[FloatingIPFilter](#floatingipfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[FloatingIPFilter](#floatingipfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### FloatingIPResourceSpec @@ -685,14 +1216,14 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the floatingip. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `floatingNetworkRef` _[KubernetesNameRef](#kubernetesnameref)_ | floatingNetworkRef references the network to which the floatingip is associated. | | MaxLength: 253
MinLength: 1
| -| `floatingSubnetRef` _[KubernetesNameRef](#kubernetesnameref)_ | floatingSubnetRef references the subnet to which the floatingip is associated. | | MaxLength: 253
MinLength: 1
| -| `floatingIP` _[IPvAny](#ipvany)_ | floatingIP is the IP that will be assigned to the floatingip. If not set, it will
be assigned automatically. | | MaxLength: 45
MinLength: 1
| -| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to the ORC Port which this resource is associated with. | | MaxLength: 253
MinLength: 1
| -| `fixedIP` _[IPvAny](#ipvany)_ | fixedIP is the IP address of the port to which the floatingip is associated. | | MaxLength: 45
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the floatingip. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `floatingNetworkRef` _[KubernetesNameRef](#kubernetesnameref)_ | floatingNetworkRef references the network to which the floatingip is associated. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `floatingSubnetRef` _[KubernetesNameRef](#kubernetesnameref)_ | floatingSubnetRef references the subnet to which the floatingip is associated. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `floatingIP` _[IPvAny](#ipvany)_ | floatingIP is the IP that will be assigned to the floatingip. If not set, it will
be assigned automatically. | | MaxLength: 45
MinLength: 1
Optional: \{\}
| +| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to the ORC Port which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `fixedIP` _[IPvAny](#ipvany)_ | fixedIP is the IP address of the port to which the floatingip is associated. | | MaxLength: 45
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### FloatingIPResourceStatus @@ -708,19 +1239,19 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `floatingNetworkID` _string_ | floatingNetworkID is the ID of the network to which the floatingip is associated. | | MaxLength: 1024
| -| `floatingIP` _string_ | floatingIP is the IP address of the floatingip. | | MaxLength: 1024
| -| `portID` _string_ | portID is the ID of the port to which the floatingip is associated. | | MaxLength: 1024
| -| `fixedIP` _string_ | fixedIP is the IP address of the port to which the floatingip is associated. | | MaxLength: 1024
| -| `tenantID` _string_ | tenantID is the project owner of the resource. | | MaxLength: 1024
| -| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
| -| `status` _string_ | status indicates the current status of the resource. | | MaxLength: 1024
| -| `routerID` _string_ | routerID is the ID of the router to which the floatingip is associated. | | MaxLength: 1024
| -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
| -| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | | -| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | | -| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | | +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `floatingNetworkID` _string_ | floatingNetworkID is the ID of the network to which the floatingip is associated. | | MaxLength: 1024
Optional: \{\}
| +| `floatingIP` _string_ | floatingIP is the IP address of the floatingip. | | MaxLength: 1024
Optional: \{\}
| +| `portID` _string_ | portID is the ID of the port to which the floatingip is associated. | | MaxLength: 1024
Optional: \{\}
| +| `fixedIP` _string_ | fixedIP is the IP address of the port to which the floatingip is associated. | | MaxLength: 1024
Optional: \{\}
| +| `tenantID` _string_ | tenantID is the project owner of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `status` _string_ | status indicates the current status of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `routerID` _string_ | routerID is the ID of the router to which the floatingip is associated. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
| #### FloatingIPSpec @@ -736,11 +1267,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[FloatingIPImport](#floatingipimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[FloatingIPResourceSpec](#floatingipresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[FloatingIPImport](#floatingipimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[FloatingIPResourceSpec](#floatingipresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### FloatingIPStatus @@ -756,9 +1288,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[FloatingIPResourceStatus](#floatingipresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[FloatingIPResourceStatus](#floatingipresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### Group @@ -775,9 +1308,9 @@ Group is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Group` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[GroupSpec](#groupspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[GroupStatus](#groupstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[GroupSpec](#groupspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[GroupStatus](#groupstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### GroupFilter @@ -794,8 +1327,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
| -| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
| +| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### GroupImport @@ -814,8 +1347,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[GroupFilter](#groupfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[GroupFilter](#groupfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### GroupResourceSpec @@ -831,9 +1364,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
| +| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### GroupResourceStatus @@ -849,9 +1382,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `domainID` _string_ | domainID is the ID of the Domain to which the resource is associated. | | MaxLength: 1024
| +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `domainID` _string_ | domainID is the ID of the Domain to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| #### GroupSpec @@ -867,11 +1400,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[GroupImport](#groupimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[GroupResourceSpec](#groupresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[GroupImport](#groupimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[GroupResourceSpec](#groupresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### GroupStatus @@ -887,9 +1421,55 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[GroupResourceStatus](#groupresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[GroupResourceStatus](#groupresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + +#### HTTPMethod + +_Underlying type:_ _string_ + + + +_Validation:_ +- Enum: [CONNECT DELETE GET HEAD OPTIONS PATCH POST PUT TRACE] + +_Appears in:_ +- [ApplicationCredentialAccessRule](#applicationcredentialaccessrule) + +| Field | Description | +| --- | --- | +| `CONNECT` | | +| `DELETE` | | +| `GET` | | +| `HEAD` | | +| `OPTIONS` | | +| `PATCH` | | +| `POST` | | +| `PUT` | | +| `TRACE` | | + + +#### HostID + + + +HostID specifies how to determine the host ID for port binding. +Exactly one of the fields must be set. + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [PortResourceSpec](#portresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id is the literal host ID string to use for binding:host_id.
This is mutually exclusive with serverRef. | | MaxLength: 36
Optional: \{\}
| +| `serverRef` _[KubernetesNameRef](#kubernetesnameref)_ | serverRef is a reference to an ORC Server resource from which to
retrieve the hostID for port binding. The hostID will be read from
the Server's status.resource.hostID field.
This is mutually exclusive with id. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### HostRoute @@ -905,8 +1485,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `destination` _[CIDR](#cidr)_ | destination for the additional route. | | Format: cidr
MaxLength: 49
MinLength: 1
| -| `nextHop` _[IPvAny](#ipvany)_ | nextHop for the additional route. | | MaxLength: 45
MinLength: 1
| +| `destination` _[CIDR](#cidr)_ | destination for the additional route. | | Format: cidr
MaxLength: 49
MinLength: 1
Required: \{\}
| +| `nextHop` _[IPvAny](#ipvany)_ | nextHop for the additional route. | | MaxLength: 45
MinLength: 1
Required: \{\}
| #### HostRouteStatus @@ -922,8 +1502,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `destination` _string_ | destination for the additional route. | | MaxLength: 1024
| -| `nextHop` _string_ | nextHop for the additional route. | | MaxLength: 1024
| +| `destination` _string_ | destination for the additional route. | | MaxLength: 1024
Optional: \{\}
| +| `nextHop` _string_ | nextHop for the additional route. | | MaxLength: 1024
Optional: \{\}
| #### IPVersion @@ -936,6 +1516,8 @@ _Validation:_ - Enum: [4 6] _Appears in:_ +- [AddressScopeFilter](#addressscopefilter) +- [AddressScopeResourceSpec](#addressscoperesourcespec) - [SubnetFilter](#subnetfilter) - [SubnetResourceSpec](#subnetresourcespec) @@ -970,8 +1552,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `addressMode` _[IPv6AddressMode](#ipv6addressmode)_ | addressMode specifies mechanisms for assigning IPv6 IP addresses. | | Enum: [slaac dhcpv6-stateful dhcpv6-stateless]
| -| `raMode` _[IPv6RAMode](#ipv6ramode)_ | raMode specifies the IPv6 router advertisement mode. It specifies whether
the networking service should transmit ICMPv6 packets. | | Enum: [slaac dhcpv6-stateful dhcpv6-stateless]
| +| `addressMode` _[IPv6AddressMode](#ipv6addressmode)_ | addressMode specifies mechanisms for assigning IPv6 IP addresses. | | Enum: [slaac dhcpv6-stateful dhcpv6-stateless]
Optional: \{\}
| +| `raMode` _[IPv6RAMode](#ipv6ramode)_ | raMode specifies the IPv6 router advertisement mode. It specifies whether
the networking service should transmit ICMPv6 packets. | | Enum: [slaac dhcpv6-stateful dhcpv6-stateless]
Optional: \{\}
| #### IPv6RAMode @@ -1025,9 +1607,9 @@ Image is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Image` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[ImageSpec](#imagespec)_ | spec specifies the desired state of the resource. | | | -| `status` _[ImageStatus](#imagestatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[ImageSpec](#imagespec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[ImageStatus](#imagestatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### ImageCompression @@ -1086,9 +1668,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `containerFormat` _[ImageContainerFormat](#imagecontainerformat)_ | containerFormat is the format of the image container.
qcow2 and raw images do not usually have a container. This is specified as "bare", which is also the default.
Permitted values are ami, ari, aki, bare, compressed, ovf, ova, and docker. | bare | Enum: [ami ari aki bare ovf ova docker compressed]
| -| `diskFormat` _[ImageDiskFormat](#imagediskformat)_ | diskFormat is the format of the disk image.
Normal values are "qcow2", or "raw". Glance may be configured to support others. | | Enum: [ami ari aki vhd vhdx vmdk raw qcow2 vdi ploop iso]
| -| `download` _[ImageContentSourceDownload](#imagecontentsourcedownload)_ | download describes how to obtain image data by downloading it from a URL.
Must be set when creating a managed image. | | | +| `containerFormat` _[ImageContainerFormat](#imagecontainerformat)_ | containerFormat is the format of the image container.
qcow2 and raw images do not usually have a container. This is specified as "bare", which is also the default.
Permitted values are ami, ari, aki, bare, compressed, ovf, ova, and docker. | bare | Enum: [ami ari aki bare ovf ova docker compressed]
Optional: \{\}
| +| `diskFormat` _[ImageDiskFormat](#imagediskformat)_ | diskFormat is the format of the disk image.
Normal values are "qcow2", or "raw". Glance may be configured to support others. | | Enum: [ami ari aki vhd vhdx vmdk raw qcow2 vdi ploop iso]
Required: \{\}
| +| `download` _[ImageContentSourceDownload](#imagecontentsourcedownload)_ | download describes how to obtain image data by downloading it from a URL.
Must be set when creating a managed image. | | Required: \{\}
| #### ImageContentSourceDownload @@ -1104,9 +1686,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `url` _string_ | url containing image data | | Format: uri
MaxLength: 2048
| -| `decompress` _[ImageCompression](#imagecompression)_ | decompress specifies that the source data must be decompressed with the
given compression algorithm before being stored. Specifying Decompress
will disable the use of Glance's web-download, as web-download cannot
currently deterministically decompress downloaded content. | | Enum: [xz gz bz2]
| -| `hash` _[ImageHash](#imagehash)_ | hash is a hash which will be used to verify downloaded data, i.e.
before any decompression. If not specified, no hash verification will be
performed. Specifying a Hash will disable the use of Glance's
web-download, as web-download cannot currently deterministically verify
the hash of downloaded content. | | | +| `url` _string_ | url containing image data | | Format: uri
MaxLength: 2048
Required: \{\}
| +| `decompress` _[ImageCompression](#imagecompression)_ | decompress specifies that the source data must be decompressed with the
given compression algorithm before being stored. Specifying Decompress
will disable the use of Glance's web-download, as web-download cannot
currently deterministically decompress downloaded content. | | Enum: [xz gz bz2]
Optional: \{\}
| +| `hash` _[ImageHash](#imagehash)_ | hash is a hash which will be used to verify downloaded data, i.e.
before any decompression. If not specified, no hash verification will be
performed. Specifying a Hash will disable the use of Glance's
web-download, as web-download cannot currently deterministically verify
the hash of downloaded content. | | Optional: \{\}
| #### ImageDiskFormat @@ -1150,9 +1732,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name specifies the name of a Glance image | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `visibility` _[ImageVisibility](#imagevisibility)_ | visibility specifies the visibility of a Glance image. | | Enum: [public private shared community]
| -| `tags` _[ImageTag](#imagetag) array_ | tags is the list of tags on the resource. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name specifies the name of a Glance image | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `visibility` _[ImageVisibility](#imagevisibility)_ | visibility specifies the visibility of a Glance image. | | Enum: [public private shared community]
Optional: \{\}
| +| `tags` _[ImageTag](#imagetag) array_ | tags is the list of tags on the resource. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| #### ImageHWBus @@ -1185,8 +1767,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `algorithm` _[ImageHashAlgorithm](#imagehashalgorithm)_ | algorithm is the hash algorithm used to generate value. | | Enum: [md5 sha1 sha256 sha512]
| -| `value` _string_ | value is the hash of the image data using Algorithm. It must be hex encoded using lowercase letters. | | MaxLength: 1024
MinLength: 1
Pattern: `^[0-9a-f]+$`
| +| `algorithm` _[ImageHashAlgorithm](#imagehashalgorithm)_ | algorithm is the hash algorithm used to generate value. | | Enum: [md5 sha1 sha256 sha512]
Required: \{\}
| +| `value` _string_ | value is the hash of the image data using Algorithm. It must be hex encoded using lowercase letters. | | MaxLength: 1024
MinLength: 1
Pattern: `^[0-9a-f]+$`
Required: \{\}
| #### ImageHashAlgorithm @@ -1225,8 +1807,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[ImageFilter](#imagefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[ImageFilter](#imagefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### ImageProperties @@ -1242,12 +1824,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `architecture` _string_ | architecture is the CPU architecture that must be supported by the hypervisor. | | Enum: [aarch64 alpha armv7l cris i686 ia64 lm32 m68k microblaze microblazeel mips mipsel mips64 mips64el openrisc parisc parisc64 ppc ppc64 ppcemb s390 s390x sh4 sh4eb sparc sparc64 unicore32 x86_64 xtensa xtensaeb]
| -| `hypervisorType` _string_ | hypervisorType is the hypervisor type | | Enum: [hyperv ironic lxc qemu uml vmware xen]
| -| `minDiskGB` _integer_ | minDiskGB is the minimum amount of disk space in GB that is required to boot the image | | Minimum: 1
| -| `minMemoryMB` _integer_ | minMemoryMB is the minimum amount of RAM in MB that is required to boot the image. | | Minimum: 1
| -| `hardware` _[ImagePropertiesHardware](#imagepropertieshardware)_ | hardware is a set of properties which control the virtual hardware
created by Nova. | | | -| `operatingSystem` _[ImagePropertiesOperatingSystem](#imagepropertiesoperatingsystem)_ | operatingSystem is a set of properties that specify and influence the behavior
of the operating system within the virtual machine. | | | +| `architecture` _string_ | architecture is the CPU architecture that must be supported by the hypervisor. | | Enum: [aarch64 alpha armv7l cris i686 ia64 lm32 m68k microblaze microblazeel mips mipsel mips64 mips64el openrisc parisc parisc64 ppc ppc64 ppcemb s390 s390x sh4 sh4eb sparc sparc64 unicore32 x86_64 xtensa xtensaeb]
Optional: \{\}
| +| `hypervisorType` _string_ | hypervisorType is the hypervisor type | | Enum: [hyperv ironic lxc qemu uml vmware xen]
Optional: \{\}
| +| `minDiskGB` _integer_ | minDiskGB is the minimum amount of disk space in GB that is required to boot the image | | Minimum: 1
Optional: \{\}
| +| `minMemoryMB` _integer_ | minMemoryMB is the minimum amount of RAM in MB that is required to boot the image. | | Minimum: 1
Optional: \{\}
| +| `hardware` _[ImagePropertiesHardware](#imagepropertieshardware)_ | hardware is a set of properties which control the virtual hardware
created by Nova. | | Optional: \{\}
| +| `operatingSystem` _[ImagePropertiesOperatingSystem](#imagepropertiesoperatingsystem)_ | operatingSystem is a set of properties that specify and influence the behavior
of the operating system within the virtual machine. | | Optional: \{\}
| #### ImagePropertiesHardware @@ -1263,17 +1845,17 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `cpuSockets` _integer_ | cpuSockets is the preferred number of sockets to expose to the guest | | Minimum: 1
| -| `cpuCores` _integer_ | cpuCores is the preferred number of cores to expose to the guest | | Minimum: 1
| -| `cpuThreads` _integer_ | cpuThreads is the preferred number of threads to expose to the guest | | Minimum: 1
| -| `cpuPolicy` _string_ | cpuPolicy is used to pin the virtual CPUs (vCPUs) of instances to the
host's physical CPU cores (pCPUs). Host aggregates should be used to
separate these pinned instances from unpinned instances as the latter
will not respect the resourcing requirements of the former.
Permitted values are shared (the default), and dedicated.
shared: The guest vCPUs will be allowed to freely float across host
pCPUs, albeit potentially constrained by NUMA policy.
dedicated: The guest vCPUs will be strictly pinned to a set of host
pCPUs. In the absence of an explicit vCPU topology request, the
drivers typically expose all vCPUs as sockets with one core and one
thread. When strict CPU pinning is in effect the guest CPU topology
will be setup to match the topology of the CPUs to which it is
pinned. This option implies an overcommit ratio of 1.0. For example,
if a two vCPU guest is pinned to a single host core with two threads,
then the guest will get a topology of one socket, one core, two
threads. | | Enum: [shared dedicated]
| -| `cpuThreadPolicy` _string_ | cpuThreadPolicy further refines a CPUPolicy of 'dedicated' by stating
how hardware CPU threads in a simultaneous multithreading-based (SMT)
architecture be used. SMT-based architectures include Intel
processors with Hyper-Threading technology. In these architectures,
processor cores share a number of components with one or more other
cores. Cores in such architectures are commonly referred to as
hardware threads, while the cores that a given core share components
with are known as thread siblings.
Permitted values are prefer (the default), isolate, and require.
prefer: The host may or may not have an SMT architecture. Where an
SMT architecture is present, thread siblings are preferred.
isolate: The host must not have an SMT architecture or must emulate a
non-SMT architecture. If the host does not have an SMT architecture,
each vCPU is placed on a different core as expected. If the host does
have an SMT architecture - that is, one or more cores have thread
siblings - then each vCPU is placed on a different physical core. No
vCPUs from other guests are placed on the same core. All but one
thread sibling on each utilized core is therefore guaranteed to be
unusable.
require: The host must have an SMT architecture. Each vCPU is
allocated on thread siblings. If the host does not have an SMT
architecture, then it is not used. If the host has an SMT
architecture, but not enough cores with free thread siblings are
available, then scheduling fails. | | Enum: [prefer isolate require]
| -| `cdromBus` _[ImageHWBus](#imagehwbus)_ | cdromBus specifies the type of disk controller to attach CD-ROM devices to. | | Enum: [scsi virtio uml xen ide usb lxc]
| -| `diskBus` _[ImageHWBus](#imagehwbus)_ | diskBus specifies the type of disk controller to attach disk devices to. | | Enum: [scsi virtio uml xen ide usb lxc]
| -| `scsiModel` _string_ | scsiModel enables the use of VirtIO SCSI (virtio-scsi) to provide
block device access for compute instances; by default, instances use
VirtIO Block (virtio-blk). VirtIO SCSI is a para-virtualized SCSI
controller device that provides improved scalability and performance,
and supports advanced SCSI hardware.
The only permitted value is virtio-scsi. | | Enum: [virtio-scsi]
| -| `vifModel` _string_ | vifModel specifies the model of virtual network interface device to use.
Permitted values are e1000, e1000e, ne2k_pci, pcnet, rtl8139, virtio,
and vmxnet3. | | Enum: [e1000 e1000e ne2k_pci pcnet rtl8139 virtio vmxnet3]
| -| `rngModel` _string_ | rngModel adds a random-number generator device to the image’s instances.
This image property by itself does not guarantee that a hardware RNG will be used;
it expresses a preference that may or may not be satisfied depending upon Nova configuration. | | MaxLength: 255
| -| `qemuGuestAgent` _boolean_ | qemuGuestAgent enables QEMU guest agent. | | | +| `cpuSockets` _integer_ | cpuSockets is the preferred number of sockets to expose to the guest | | Minimum: 1
Optional: \{\}
| +| `cpuCores` _integer_ | cpuCores is the preferred number of cores to expose to the guest | | Minimum: 1
Optional: \{\}
| +| `cpuThreads` _integer_ | cpuThreads is the preferred number of threads to expose to the guest | | Minimum: 1
Optional: \{\}
| +| `cpuPolicy` _string_ | cpuPolicy is used to pin the virtual CPUs (vCPUs) of instances to the
host's physical CPU cores (pCPUs). Host aggregates should be used to
separate these pinned instances from unpinned instances as the latter
will not respect the resourcing requirements of the former.
Permitted values are shared (the default), and dedicated.
shared: The guest vCPUs will be allowed to freely float across host
pCPUs, albeit potentially constrained by NUMA policy.
dedicated: The guest vCPUs will be strictly pinned to a set of host
pCPUs. In the absence of an explicit vCPU topology request, the
drivers typically expose all vCPUs as sockets with one core and one
thread. When strict CPU pinning is in effect the guest CPU topology
will be setup to match the topology of the CPUs to which it is
pinned. This option implies an overcommit ratio of 1.0. For example,
if a two vCPU guest is pinned to a single host core with two threads,
then the guest will get a topology of one socket, one core, two
threads. | | Enum: [shared dedicated]
Optional: \{\}
| +| `cpuThreadPolicy` _string_ | cpuThreadPolicy further refines a CPUPolicy of 'dedicated' by stating
how hardware CPU threads in a simultaneous multithreading-based (SMT)
architecture be used. SMT-based architectures include Intel
processors with Hyper-Threading technology. In these architectures,
processor cores share a number of components with one or more other
cores. Cores in such architectures are commonly referred to as
hardware threads, while the cores that a given core share components
with are known as thread siblings.
Permitted values are prefer (the default), isolate, and require.
prefer: The host may or may not have an SMT architecture. Where an
SMT architecture is present, thread siblings are preferred.
isolate: The host must not have an SMT architecture or must emulate a
non-SMT architecture. If the host does not have an SMT architecture,
each vCPU is placed on a different core as expected. If the host does
have an SMT architecture - that is, one or more cores have thread
siblings - then each vCPU is placed on a different physical core. No
vCPUs from other guests are placed on the same core. All but one
thread sibling on each utilized core is therefore guaranteed to be
unusable.
require: The host must have an SMT architecture. Each vCPU is
allocated on thread siblings. If the host does not have an SMT
architecture, then it is not used. If the host has an SMT
architecture, but not enough cores with free thread siblings are
available, then scheduling fails. | | Enum: [prefer isolate require]
Optional: \{\}
| +| `cdromBus` _[ImageHWBus](#imagehwbus)_ | cdromBus specifies the type of disk controller to attach CD-ROM devices to. | | Enum: [scsi virtio uml xen ide usb lxc]
Optional: \{\}
| +| `diskBus` _[ImageHWBus](#imagehwbus)_ | diskBus specifies the type of disk controller to attach disk devices to. | | Enum: [scsi virtio uml xen ide usb lxc]
Optional: \{\}
| +| `scsiModel` _string_ | scsiModel enables the use of VirtIO SCSI (virtio-scsi) to provide
block device access for compute instances; by default, instances use
VirtIO Block (virtio-blk). VirtIO SCSI is a para-virtualized SCSI
controller device that provides improved scalability and performance,
and supports advanced SCSI hardware.
The only permitted value is virtio-scsi. | | Enum: [virtio-scsi]
Optional: \{\}
| +| `vifModel` _string_ | vifModel specifies the model of virtual network interface device to use.
Permitted values are e1000, e1000e, ne2k_pci, pcnet, rtl8139, virtio,
and vmxnet3. | | Enum: [e1000 e1000e ne2k_pci pcnet rtl8139 virtio vmxnet3]
Optional: \{\}
| +| `rngModel` _string_ | rngModel adds a random-number generator device to the image’s instances.
This image property by itself does not guarantee that a hardware RNG will be used;
it expresses a preference that may or may not be satisfied depending upon Nova configuration. | | MaxLength: 255
Optional: \{\}
| +| `qemuGuestAgent` _boolean_ | qemuGuestAgent enables QEMU guest agent. | | Optional: \{\}
| #### ImagePropertiesOperatingSystem @@ -1289,8 +1871,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `distro` _string_ | distro is the common name of the operating system distribution in lowercase. | | Enum: [arch centos debian fedora freebsd gentoo mandrake mandriva mes msdos netbsd netware openbsd opensolaris opensuse rocky rhel sled ubuntu windows]
| -| `version` _string_ | version is the operating system version as specified by the distributor. | | MaxLength: 255
| +| `distro` _string_ | distro is the common name of the operating system distribution in lowercase. | | Enum: [arch centos debian fedora freebsd gentoo mandrake mandriva mes msdos netbsd netware openbsd opensolaris opensuse rocky rhel sled ubuntu windows]
Optional: \{\}
| +| `version` _string_ | version is the operating system version as specified by the distributor. | | MaxLength: 255
Optional: \{\}
| #### ImageResourceSpec @@ -1306,12 +1888,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created Glance image. If not specified, the
name of the Image object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `protected` _boolean_ | protected specifies that the image is protected from deletion.
If not specified, the default is false. | | | -| `tags` _[ImageTag](#imagetag) array_ | tags is a list of tags which will be applied to the image. A tag has a maximum length of 255 characters. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `visibility` _[ImageVisibility](#imagevisibility)_ | visibility of the image | | Enum: [public private shared community]
| -| `properties` _[ImageProperties](#imageproperties)_ | properties is metadata available to consumers of the image | | | -| `content` _[ImageContent](#imagecontent)_ | content specifies how to obtain the image content. | | | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created Glance image. If not specified, the
name of the Image object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `protected` _boolean_ | protected specifies that the image is protected from deletion.
If not specified, the default is false. | | Optional: \{\}
| +| `tags` _[ImageTag](#imagetag) array_ | tags is a list of tags which will be applied to the image. A tag has a maximum length of 255 characters. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `visibility` _[ImageVisibility](#imagevisibility)_ | visibility of the image | | Enum: [public private shared community]
Optional: \{\}
| +| `properties` _[ImageProperties](#imageproperties)_ | properties is metadata available to consumers of the image | | Optional: \{\}
| +| `content` _[ImageContent](#imagecontent)_ | content specifies how to obtain the image content. | | Optional: \{\}
| #### ImageResourceStatus @@ -1327,14 +1909,14 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the image. Might not be unique. | | MaxLength: 1024
| -| `status` _string_ | status is the image status as reported by Glance | | MaxLength: 1024
| -| `protected` _boolean_ | protected specifies that the image is protected from deletion. | | | -| `visibility` _string_ | visibility of the image | | MaxLength: 1024
| -| `hash` _[ImageHash](#imagehash)_ | hash is the hash of the image data published by Glance. Note that this is
a hash of the data stored internally by Glance, which will have been
decompressed and potentially format converted depending on server-side
configuration which is not visible to clients. It is expected that this
hash will usually differ from the download hash. | | | -| `sizeB` _integer_ | sizeB is the size of the image data, in bytes | | | -| `virtualSizeB` _integer_ | virtualSizeB is the size of the disk the image data represents, in bytes | | | -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
| +| `name` _string_ | name is a Human-readable name for the image. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `status` _string_ | status is the image status as reported by Glance | | MaxLength: 1024
Optional: \{\}
| +| `protected` _boolean_ | protected specifies that the image is protected from deletion. | | Optional: \{\}
| +| `visibility` _string_ | visibility of the image | | MaxLength: 1024
Optional: \{\}
| +| `hash` _[ImageHash](#imagehash)_ | hash is the hash of the image data published by Glance. Note that this is
a hash of the data stored internally by Glance, which will have been
decompressed and potentially format converted depending on server-side
configuration which is not visible to clients. It is expected that this
hash will usually differ from the download hash. | | Optional: \{\}
| +| `sizeB` _integer_ | sizeB is the size of the image data, in bytes | | Optional: \{\}
| +| `virtualSizeB` _integer_ | virtualSizeB is the size of the disk the image data represents, in bytes | | Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| #### ImageSpec @@ -1350,11 +1932,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[ImageImport](#imageimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[ImageResourceSpec](#imageresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[ImageImport](#imageimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[ImageResourceSpec](#imageresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### ImageStatus @@ -1370,10 +1953,11 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[ImageResourceStatus](#imageresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | -| `downloadAttempts` _integer_ | downloadAttempts is the number of times the controller has attempted to download the image contents | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[ImageResourceStatus](#imageresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| +| `downloadAttempts` _integer_ | downloadAttempts is the number of times the controller has attempted to download the image contents | | Optional: \{\}
| #### ImageStatusExtra @@ -1389,7 +1973,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `downloadAttempts` _integer_ | downloadAttempts is the number of times the controller has attempted to download the image contents | | | +| `downloadAttempts` _integer_ | downloadAttempts is the number of times the controller has attempted to download the image contents | | Optional: \{\}
| #### ImageTag @@ -1443,9 +2027,9 @@ KeyPair is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `KeyPair` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[KeyPairSpec](#keypairspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[KeyPairStatus](#keypairstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[KeyPairSpec](#keypairspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[KeyPairStatus](#keypairstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### KeyPairFilter @@ -1462,7 +2046,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing Keypair | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing Keypair | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| #### KeyPairImport @@ -1481,8 +2065,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the name of an existing resource. Note: This resource uses
the resource name as the unique identifier, not a UUID.
When specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | | -| `filter` _[KeyPairFilter](#keypairfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the name of an existing resource. Note: This resource uses
the resource name as the unique identifier, not a UUID.
When specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | MaxLength: 1024
Optional: \{\}
| +| `filter` _[KeyPairFilter](#keypairfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### KeyPairResourceSpec @@ -1498,9 +2082,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `type` _string_ | type specifies the type of the Keypair. Allowed values are ssh or x509.
If not specified, defaults to ssh. | | Enum: [ssh x509]
| -| `publicKey` _string_ | publicKey is the public key to import. | | MaxLength: 16384
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `type` _string_ | type specifies the type of the Keypair. Allowed values are ssh or x509.
If not specified, defaults to ssh. | | Enum: [ssh x509]
Optional: \{\}
| +| `publicKey` _string_ | publicKey is the public key to import. | | MaxLength: 16384
MinLength: 1
Required: \{\}
| #### KeyPairResourceStatus @@ -1516,10 +2100,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
| -| `fingerprint` _string_ | fingerprint is the fingerprint of the public key | | MaxLength: 1024
| -| `publicKey` _string_ | publicKey is the public key of the Keypair | | MaxLength: 16384
| -| `type` _string_ | type is the type of the Keypair (ssh or x509) | | MaxLength: 64
| +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `fingerprint` _string_ | fingerprint is the fingerprint of the public key | | MaxLength: 1024
Optional: \{\}
| +| `publicKey` _string_ | publicKey is the public key of the Keypair | | MaxLength: 16384
Optional: \{\}
| +| `type` _string_ | type is the type of the Keypair (ssh or x509) | | MaxLength: 64
Optional: \{\}
| #### KeyPairSpec @@ -1535,11 +2119,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[KeyPairImport](#keypairimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[KeyPairResourceSpec](#keypairresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[KeyPairImport](#keypairimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[KeyPairResourceSpec](#keypairresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### KeyPairStatus @@ -1555,9 +2140,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[KeyPairResourceStatus](#keypairresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[KeyPairResourceStatus](#keypairresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### KeystoneName @@ -1611,15 +2197,27 @@ _Validation:_ _Appears in:_ - [Address](#address) +- [AddressScopeFilter](#addressscopefilter) +- [AddressScopeResourceSpec](#addressscoperesourcespec) +- [ApplicationCredentialAccessRule](#applicationcredentialaccessrule) +- [ApplicationCredentialFilter](#applicationcredentialfilter) +- [ApplicationCredentialResourceSpec](#applicationcredentialresourcespec) +- [EndpointFilter](#endpointfilter) +- [EndpointResourceSpec](#endpointresourcespec) - [ExternalGateway](#externalgateway) - [FloatingIPFilter](#floatingipfilter) - [FloatingIPResourceSpec](#floatingipresourcespec) - [GroupFilter](#groupfilter) - [GroupResourceSpec](#groupresourcespec) +- [HostID](#hostid) - [NetworkFilter](#networkfilter) - [NetworkResourceSpec](#networkresourcespec) - [PortFilter](#portfilter) - [PortResourceSpec](#portresourcespec) +- [ProjectFilter](#projectfilter) +- [ProjectResourceSpec](#projectresourcespec) +- [RoleAssignmentFilter](#roleassignmentfilter) +- [RoleAssignmentResourceSpec](#roleassignmentresourcespec) - [RoleFilter](#rolefilter) - [RoleResourceSpec](#roleresourcespec) - [RouterFilter](#routerfilter) @@ -1627,12 +2225,20 @@ _Appears in:_ - [RouterResourceSpec](#routerresourcespec) - [SecurityGroupFilter](#securitygroupfilter) - [SecurityGroupResourceSpec](#securitygroupresourcespec) +- [ServerBootVolumeSpec](#serverbootvolumespec) - [ServerPortSpec](#serverportspec) - [ServerResourceSpec](#serverresourcespec) +- [ServerSchedulerHints](#serverschedulerhints) - [ServerVolumeSpec](#servervolumespec) +- [ShareNetworkResourceSpec](#sharenetworkresourcespec) - [SubnetFilter](#subnetfilter) - [SubnetResourceSpec](#subnetresourcespec) +- [TrunkFilter](#trunkfilter) +- [TrunkResourceSpec](#trunkresourcespec) +- [TrunkSubportSpec](#trunksubportspec) - [UserDataSpec](#userdataspec) +- [UserFilter](#userfilter) +- [UserResourceSpec](#userresourcespec) - [VolumeResourceSpec](#volumeresourcespec) @@ -1676,7 +2282,10 @@ _Appears in:_ _Appears in:_ +- [AddressScopeSpec](#addressscopespec) +- [ApplicationCredentialSpec](#applicationcredentialspec) - [DomainSpec](#domainspec) +- [EndpointSpec](#endpointspec) - [FlavorSpec](#flavorspec) - [FloatingIPSpec](#floatingipspec) - [GroupSpec](#groupspec) @@ -1685,19 +2294,23 @@ _Appears in:_ - [NetworkSpec](#networkspec) - [PortSpec](#portspec) - [ProjectSpec](#projectspec) +- [RoleAssignmentSpec](#roleassignmentspec) - [RoleSpec](#rolespec) - [RouterSpec](#routerspec) - [SecurityGroupSpec](#securitygroupspec) - [ServerGroupSpec](#servergroupspec) - [ServerSpec](#serverspec) - [ServiceSpec](#servicespec) +- [ShareNetworkSpec](#sharenetworkspec) - [SubnetSpec](#subnetspec) +- [TrunkSpec](#trunkspec) +- [UserSpec](#userspec) - [VolumeSpec](#volumespec) - [VolumeTypeSpec](#volumetypespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `onDelete` _[OnDelete](#ondelete)_ | onDelete specifies the behaviour of the controller when the ORC
object is deleted. Options are `delete` - delete the OpenStack resource;
`detach` - do not delete the OpenStack resource. If not specified, the
default is `delete`. | delete | Enum: [delete detach]
| +| `onDelete` _[OnDelete](#ondelete)_ | onDelete specifies the behaviour of the controller when the ORC
object is deleted. Options are `delete` - delete the OpenStack resource;
`detach` - do not delete the OpenStack resource. If not specified, the
default is `delete`. | delete | Enum: [delete detach]
Optional: \{\}
| #### ManagementPolicy @@ -1710,7 +2323,10 @@ _Validation:_ - Enum: [managed unmanaged] _Appears in:_ +- [AddressScopeSpec](#addressscopespec) +- [ApplicationCredentialSpec](#applicationcredentialspec) - [DomainSpec](#domainspec) +- [EndpointSpec](#endpointspec) - [FlavorSpec](#flavorspec) - [FloatingIPSpec](#floatingipspec) - [GroupSpec](#groupspec) @@ -1719,13 +2335,17 @@ _Appears in:_ - [NetworkSpec](#networkspec) - [PortSpec](#portspec) - [ProjectSpec](#projectspec) +- [RoleAssignmentSpec](#roleassignmentspec) - [RoleSpec](#rolespec) - [RouterSpec](#routerspec) - [SecurityGroupSpec](#securitygroupspec) - [ServerGroupSpec](#servergroupspec) - [ServerSpec](#serverspec) - [ServiceSpec](#servicespec) +- [ShareNetworkSpec](#sharenetworkspec) - [SubnetSpec](#subnetspec) +- [TrunkSpec](#trunkspec) +- [UserSpec](#userspec) - [VolumeSpec](#volumespec) - [VolumeTypeSpec](#volumetypespec) @@ -1749,9 +2369,9 @@ Network is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Network` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[NetworkSpec](#networkspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[NetworkStatus](#networkstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[NetworkSpec](#networkspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[NetworkStatus](#networkstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### NetworkFilter @@ -1768,14 +2388,14 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `external` _boolean_ | external indicates whether the network has an external routing
facility that’s not managed by the networking service. | | | -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `external` _boolean_ | external indicates whether the network has an external routing
facility that’s not managed by the networking service. | | Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| #### NetworkImport @@ -1794,8 +2414,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[NetworkFilter](#networkfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[NetworkFilter](#networkfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### NetworkResourceSpec @@ -1811,17 +2431,17 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the network. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the network, which is up (true) or down (false) | | | -| `dnsDomain` _[DNSDomain](#dnsdomain)_ | dnsDomain is the DNS domain of the network | | MaxLength: 255
MinLength: 1
Pattern: `^[A-Za-z0-9]\{1,63\}(.[A-Za-z0-9-]\{1,63\})*(.[A-Za-z]\{2,63\})*.?$`
| -| `mtu` _[MTU](#mtu)_ | mtu is the the maximum transmission unit value to address
fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.
Defaults to 1500. | | Maximum: 9216
Minimum: 68
| -| `portSecurityEnabled` _boolean_ | portSecurityEnabled is the port security status of the network.
Valid values are enabled (true) and disabled (false). This value is
used as the default value of port_security_enabled field of a newly
created port. | | | -| `external` _boolean_ | external indicates whether the network has an external routing
facility that’s not managed by the networking service. | | | -| `shared` _boolean_ | shared indicates whether this resource is shared across all
projects. By default, only administrative users can change this
value. | | | -| `availabilityZoneHints` _[AvailabilityZoneHint](#availabilityzonehint) array_ | availabilityZoneHints is the availability zone candidate for the network. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the network. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the network, which is up (true) or down (false) | | Optional: \{\}
| +| `dnsDomain` _[DNSDomain](#dnsdomain)_ | dnsDomain is the DNS domain of the network | | MaxLength: 255
MinLength: 1
Pattern: `^[A-Za-z0-9]\{1,63\}(.[A-Za-z0-9-]\{1,63\})*(.[A-Za-z]\{2,63\})*.?$`
Optional: \{\}
| +| `mtu` _[MTU](#mtu)_ | mtu is the the maximum transmission unit value to address
fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6.
Defaults to 1500. | | Maximum: 9216
Minimum: 68
Optional: \{\}
| +| `portSecurityEnabled` _boolean_ | portSecurityEnabled is the port security status of the network.
Valid values are enabled (true) and disabled (false). This value is
used as the default value of port_security_enabled field of a newly
created port. | | Optional: \{\}
| +| `external` _boolean_ | external indicates whether the network has an external routing
facility that’s not managed by the networking service. | | Optional: \{\}
| +| `shared` _boolean_ | shared indicates whether this resource is shared across all
projects. By default, only administrative users can change this
value. | | Optional: \{\}
| +| `availabilityZoneHints` _[AvailabilityZoneHint](#availabilityzonehint) array_ | availabilityZoneHints is the availability zone candidate for the network. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### NetworkResourceStatus @@ -1837,23 +2457,23 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the network. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `projectID` _string_ | projectID is the project owner of the network. | | MaxLength: 1024
| -| `status` _string_ | status indicates whether network is currently operational. Possible values
include `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define
additional values. | | MaxLength: 1024
| -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
| -| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | | -| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | | -| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | | -| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the network,
which is up (true) or down (false). | | | -| `availabilityZoneHints` _string array_ | availabilityZoneHints is the availability zone candidate for the
network. | | MaxItems: 64
items:MaxLength: 1024
| -| `dnsDomain` _string_ | dnsDomain is the DNS domain of the network | | MaxLength: 1024
| -| `mtu` _integer_ | mtu is the the maximum transmission unit value to address
fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6. | | | -| `portSecurityEnabled` _boolean_ | portSecurityEnabled is the port security status of the network.
Valid values are enabled (true) and disabled (false). This value is
used as the default value of port_security_enabled field of a newly
created port. | | | -| `provider` _[ProviderPropertiesStatus](#providerpropertiesstatus)_ | provider contains provider-network properties. | | | -| `external` _boolean_ | external defines whether the network may be used for creation of
floating IPs. Only networks with this flag may be an external
gateway for routers. The network must have an external routing
facility that is not managed by the networking service. If the
network is updated from external to internal the unused floating IPs
of this network are automatically deleted when extension
floatingip-autodelete-internal is present. | | | -| `shared` _boolean_ | shared specifies whether the network resource can be accessed by any
tenant. | | | -| `subnets` _string array_ | subnets associated with this network. | | MaxItems: 256
items:MaxLength: 1024
| +| `name` _string_ | name is a Human-readable name for the network. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the project owner of the network. | | MaxLength: 1024
Optional: \{\}
| +| `status` _string_ | status indicates whether network is currently operational. Possible values
include `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define
additional values. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the network,
which is up (true) or down (false). | | Optional: \{\}
| +| `availabilityZoneHints` _string array_ | availabilityZoneHints is the availability zone candidate for the
network. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `dnsDomain` _string_ | dnsDomain is the DNS domain of the network | | MaxLength: 1024
Optional: \{\}
| +| `mtu` _integer_ | mtu is the the maximum transmission unit value to address
fragmentation. Minimum value is 68 for IPv4, and 1280 for IPv6. | | Optional: \{\}
| +| `portSecurityEnabled` _boolean_ | portSecurityEnabled is the port security status of the network.
Valid values are enabled (true) and disabled (false). This value is
used as the default value of port_security_enabled field of a newly
created port. | | Optional: \{\}
| +| `provider` _[ProviderPropertiesStatus](#providerpropertiesstatus)_ | provider contains provider-network properties. | | Optional: \{\}
| +| `external` _boolean_ | external defines whether the network may be used for creation of
floating IPs. Only networks with this flag may be an external
gateway for routers. The network must have an external routing
facility that is not managed by the networking service. If the
network is updated from external to internal the unused floating IPs
of this network are automatically deleted when extension
floatingip-autodelete-internal is present. | | Optional: \{\}
| +| `shared` _boolean_ | shared specifies whether the network resource can be accessed by any
tenant. | | Optional: \{\}
| +| `subnets` _string array_ | subnets associated with this network. | | MaxItems: 256
items:MaxLength: 1024
Optional: \{\}
| #### NetworkSpec @@ -1869,11 +2489,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[NetworkImport](#networkimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[NetworkResourceSpec](#networkresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[NetworkImport](#networkimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[NetworkResourceSpec](#networkresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### NetworkStatus @@ -1889,9 +2510,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[NetworkResourceStatus](#networkresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[NetworkResourceStatus](#networkresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### NeutronDescription @@ -1918,6 +2540,8 @@ _Appears in:_ - [SecurityGroupRule](#securitygrouprule) - [SubnetFilter](#subnetfilter) - [SubnetResourceSpec](#subnetresourcespec) +- [TrunkFilter](#trunkfilter) +- [TrunkResourceSpec](#trunkresourcespec) @@ -1935,12 +2559,13 @@ _Appears in:_ - [PortResourceStatus](#portresourcestatus) - [SecurityGroupResourceStatus](#securitygroupresourcestatus) - [SubnetResourceStatus](#subnetresourcestatus) +- [TrunkResourceStatus](#trunkresourcestatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | | -| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | | -| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | | +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
| #### NeutronTag @@ -1968,6 +2593,8 @@ _Appears in:_ - [SecurityGroupResourceSpec](#securitygroupresourcespec) - [SubnetFilter](#subnetfilter) - [SubnetResourceSpec](#subnetresourcespec) +- [TrunkFilter](#trunkfilter) +- [TrunkResourceSpec](#trunkresourcespec) @@ -2003,6 +2630,10 @@ _Validation:_ - Pattern: `^[^,]+$` _Appears in:_ +- [AddressScopeFilter](#addressscopefilter) +- [AddressScopeResourceSpec](#addressscoperesourcespec) +- [ApplicationCredentialFilter](#applicationcredentialfilter) +- [ApplicationCredentialResourceSpec](#applicationcredentialresourcespec) - [FlavorFilter](#flavorfilter) - [FlavorResourceSpec](#flavorresourcespec) - [ImageFilter](#imagefilter) @@ -2023,8 +2654,14 @@ _Appears in:_ - [ServerResourceSpec](#serverresourcespec) - [ServiceFilter](#servicefilter) - [ServiceResourceSpec](#serviceresourcespec) +- [ShareNetworkFilter](#sharenetworkfilter) +- [ShareNetworkResourceSpec](#sharenetworkresourcespec) - [SubnetFilter](#subnetfilter) - [SubnetResourceSpec](#subnetresourcespec) +- [TrunkFilter](#trunkfilter) +- [TrunkResourceSpec](#trunkresourcespec) +- [UserFilter](#userfilter) +- [UserResourceSpec](#userresourcespec) - [VolumeFilter](#volumefilter) - [VolumeResourceSpec](#volumeresourcespec) - [VolumeTypeFilter](#volumetypefilter) @@ -2046,9 +2683,9 @@ Port is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Port` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[PortSpec](#portspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[PortStatus](#portstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[PortSpec](#portspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[PortStatus](#portstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### PortFilter @@ -2065,15 +2702,16 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this port is associated with. | | MaxLength: 253
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| -| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the port,
which is up (true) or down (false). | | | -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this port is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the port,
which is up (true) or down (false). | | Optional: \{\}
| +| `macAddress` _string_ | macAddress is the MAC address of the port. | | MaxLength: 32
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| #### PortImport @@ -2092,8 +2730,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[PortFilter](#portfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[PortFilter](#portfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### PortNumber @@ -2124,8 +2762,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `min` _[PortNumber](#portnumber)_ | min is the minimum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal
to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type | | Maximum: 65535
Minimum: 0
| -| `max` _[PortNumber](#portnumber)_ | max is the maximum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal
to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code. | | Maximum: 65535
Minimum: 0
| +| `min` _[PortNumber](#portnumber)_ | min is the minimum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal
to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type | | Maximum: 65535
Minimum: 0
Required: \{\}
| +| `max` _[PortNumber](#portnumber)_ | max is the maximum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal
to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code. | | Maximum: 65535
Minimum: 0
Required: \{\}
| #### PortRangeStatus @@ -2141,8 +2779,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `min` _integer_ | min is the minimum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal
to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type | | | -| `max` _integer_ | max is the maximum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal
to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code. | | | +| `min` _integer_ | min is the minimum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be less than or equal
to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type | | Optional: \{\}
| +| `max` _integer_ | max is the maximum port number in the range that is matched by the security group rule.
If the protocol is TCP, UDP, DCCP, SCTP or UDP-Lite this value must be greater than or equal
to the port_range_min attribute value. If the protocol is ICMP, this value must be an ICMP code. | | Optional: \{\}
| #### PortResourceSpec @@ -2158,17 +2796,22 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name is a human-readable name of the port. If not set, the object's name will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this port is associated with. | | MaxLength: 253
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the port. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `allowedAddressPairs` _[AllowedAddressPair](#allowedaddresspair) array_ | allowedAddressPairs are allowed addresses associated with this port. | | MaxItems: 128
| -| `addresses` _[Address](#address) array_ | addresses are the IP addresses for the port. | | MaxItems: 128
| -| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the port,
which is up (true) or down (false). The default value is true. | true | | -| `securityGroupRefs` _[OpenStackName](#openstackname) array_ | securityGroupRefs are the names of the security groups associated
with this port. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `vnicType` _string_ | vnicType specifies the type of vNIC which this port should be
attached to. This is used to determine which mechanism driver(s) to
be used to bind the port. The valid values are normal, macvtap,
direct, baremetal, direct-physical, virtio-forwarder, smart-nic and
remote-managed, although these values will not be validated in this
API to ensure compatibility with future neutron changes or custom
implementations. What type of vNIC is actually available depends on
deployments. If not specified, the Neutron default value is used. | | MaxLength: 64
| -| `portSecurity` _[PortSecurityState](#portsecuritystate)_ | portSecurity controls port security for this port.
When set to Enabled, port security is enabled.
When set to Disabled, port security is disabled and SecurityGroupRefs must be empty.
When set to Inherit (default), it takes the value from the network level. | Inherit | Enum: [Enabled Disabled Inherit]
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name is a human-readable name of the port. If not set, the object's name will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this port is associated with. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the port. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `allowedAddressPairs` _[AllowedAddressPair](#allowedaddresspair) array_ | allowedAddressPairs are allowed addresses associated with this port. | | MaxItems: 128
Optional: \{\}
| +| `addresses` _[Address](#address) array_ | addresses are the IP addresses for the port. | | MaxItems: 128
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the port,
which is up (true) or down (false). The default value is true. | true | Optional: \{\}
| +| `securityGroupRefs` _[KubernetesNameRef](#kubernetesnameref) array_ | securityGroupRefs are references to the security groups associated
with this port. | | MaxItems: 64
MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `vnicType` _string_ | vnicType specifies the type of vNIC which this port should be
attached to. This is used to determine which mechanism driver(s) to
be used to bind the port. The valid values are normal, macvtap,
direct, baremetal, direct-physical, virtio-forwarder, smart-nic and
remote-managed, although these values will not be validated in this
API to ensure compatibility with future neutron changes or custom
implementations. What type of vNIC is actually available depends on
deployments. If not specified, the Neutron default value is used. | | MaxLength: 64
Optional: \{\}
| +| `portSecurity` _[PortSecurityState](#portsecuritystate)_ | portSecurity controls port security for this port.
When set to Enabled, port security is enabled.
When set to Disabled, port security is disabled and SecurityGroupRefs must be empty.
When set to Inherit (default), it takes the value from the network level. | Inherit | Enum: [Enabled Disabled Inherit]
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `macAddress` _string_ | macAddress is the MAC address of the port. | | MaxLength: 32
Optional: \{\}
| +| `hostID` _[HostID](#hostid)_ | hostID specifies the host where the port will be bound.
Note that when the port is attached to a server, OpenStack may
rebind the port to the server's actual compute host, which may
differ from the specified hostID if no matching scheduler hint
is used. In this case the port's status will reflect the actual
binding host, not the value specified here. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `trustedVIF` _boolean_ | trustedVIF indicates whether the VF for the port will become
trusted by physical function to perform some privileged
operations. Only admin users can create ports with this field. | | Optional: \{\}
| +| `valueSpecs` _[PortValueSpec](#portvaluespec) array_ | valueSpecs are extra parameters to include in the API request
with OpenStack. This is an extension point for the API, so what
they do and if they are supported, depends on the specific
OpenStack implementation. This was meant to work similar to the
property on Heat port resource. Since this depends on the
underlying implementation, we can't predict its fields, and
therefore, we don't know how to reconcile them in advance. Use
this field wisely and be aware of the expected behavior. | | MaxItems: 128
Optional: \{\}
| +| `propagateUplinkStatus` _boolean_ | propagateUplinkStatus represents the uplink status propagation of
the port.
The field is now immutable due to a limitation on
Dalmatian (2024.2) release, we should address this later.
https://github.com/k-orc/openstack-resource-controller/pull/641#discussion_r2694783787 | | Optional: \{\}
| #### PortResourceStatus @@ -2184,25 +2827,27 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is the human-readable name of the resource. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `networkID` _string_ | networkID is the ID of the attached network. | | MaxLength: 1024
| -| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
| -| `status` _string_ | status indicates the current status of the resource. | | MaxLength: 1024
| -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
| -| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the port,
which is up (true) or down (false). | | | -| `macAddress` _string_ | macAddress is the MAC address of the port. | | MaxLength: 1024
| -| `deviceID` _string_ | deviceID is the ID of the device that uses this port. | | MaxLength: 1024
| -| `deviceOwner` _string_ | deviceOwner is the entity type that uses this port. | | MaxLength: 1024
| -| `allowedAddressPairs` _[AllowedAddressPairStatus](#allowedaddresspairstatus) array_ | allowedAddressPairs is a set of zero or more allowed address pair
objects each where address pair object contains an IP address and
MAC address. | | MaxItems: 128
| -| `fixedIPs` _[FixedIPStatus](#fixedipstatus) array_ | fixedIPs is a set of zero or more fixed IP objects each where fixed
IP object contains an IP address and subnet ID from which the IP
address is assigned. | | MaxItems: 128
| -| `securityGroups` _string array_ | securityGroups contains the IDs of security groups applied to the port. | | MaxItems: 64
items:MaxLength: 1024
| -| `propagateUplinkStatus` _boolean_ | propagateUplinkStatus represents the uplink status propagation of
the port. | | | -| `vnicType` _string_ | vnicType is the type of vNIC which this port is attached to. | | MaxLength: 64
| -| `portSecurityEnabled` _boolean_ | portSecurityEnabled indicates whether port security is enabled or not. | | | -| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | | -| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | | -| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | | +| `name` _string_ | name is the human-readable name of the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `networkID` _string_ | networkID is the ID of the attached network. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `status` _string_ | status indicates the current status of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the port,
which is up (true) or down (false). | | Optional: \{\}
| +| `macAddress` _string_ | macAddress is the MAC address of the port. | | MaxLength: 1024
Optional: \{\}
| +| `deviceID` _string_ | deviceID is the ID of the device that uses this port. | | MaxLength: 1024
Optional: \{\}
| +| `deviceOwner` _string_ | deviceOwner is the entity type that uses this port. | | MaxLength: 1024
Optional: \{\}
| +| `allowedAddressPairs` _[AllowedAddressPairStatus](#allowedaddresspairstatus) array_ | allowedAddressPairs is a set of zero or more allowed address pair
objects each where address pair object contains an IP address and
MAC address. | | MaxItems: 128
Optional: \{\}
| +| `fixedIPs` _[FixedIPStatus](#fixedipstatus) array_ | fixedIPs is a set of zero or more fixed IP objects each where fixed
IP object contains an IP address and subnet ID from which the IP
address is assigned. | | MaxItems: 128
Optional: \{\}
| +| `securityGroups` _string array_ | securityGroups contains the IDs of security groups applied to the port. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `propagateUplinkStatus` _boolean_ | propagateUplinkStatus represents the uplink status propagation of
the port. | | Optional: \{\}
| +| `vnicType` _string_ | vnicType is the type of vNIC which this port is attached to. | | MaxLength: 64
Optional: \{\}
| +| `portSecurityEnabled` _boolean_ | portSecurityEnabled indicates whether port security is enabled or not. | | Optional: \{\}
| +| `hostID` _string_ | hostID is the ID of host where the port resides. | | MaxLength: 128
Optional: \{\}
| +| `trustedVIF` _boolean_ | trustedVIF indicates whether the VF for the port will become
trusted by physical function to perform some privileged
operations. | | Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
| #### PortSecurityState @@ -2237,11 +2882,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[PortImport](#portimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[PortResourceSpec](#portresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[PortImport](#portimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[PortResourceSpec](#portresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### PortStatus @@ -2257,9 +2903,27 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[PortResourceStatus](#portresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[PortResourceStatus](#portresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + +#### PortValueSpec + + + + + + + +_Appears in:_ +- [PortResourceSpec](#portresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `key` _string_ | key is the name of the Neutron API extension parameter. | | MaxLength: 255
MinLength: 1
Required: \{\}
| +| `value` _string_ | value is the value of the Neutron API extension parameter. | | MaxLength: 255
Required: \{\}
| #### Project @@ -2276,9 +2940,9 @@ Project is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Project` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[ProjectSpec](#projectspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[ProjectStatus](#projectstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[ProjectSpec](#projectspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[ProjectStatus](#projectstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### ProjectFilter @@ -2295,11 +2959,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
| -| `tags` _[KeystoneTag](#keystonetag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[KeystoneTag](#keystonetag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| -| `notTags` _[KeystoneTag](#keystonetag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[KeystoneTag](#keystonetag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| +| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `tags` _[KeystoneTag](#keystonetag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[KeystoneTag](#keystonetag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[KeystoneTag](#keystonetag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[KeystoneTag](#keystonetag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| #### ProjectImport @@ -2318,8 +2983,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[ProjectFilter](#projectfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[ProjectFilter](#projectfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### ProjectResourceSpec @@ -2335,10 +3000,11 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
| -| `description` _string_ | description contains a free form description of the project. | | MaxLength: 65535
MinLength: 1
| -| `enabled` _boolean_ | enabled defines whether a project is enabled or not. Default is true. | | | -| `tags` _[KeystoneTag](#keystonetag) array_ | tags is list of simple strings assigned to a project.
Tags can be used to classify projects into groups. | | MaxItems: 80
MaxLength: 255
MinLength: 1
| +| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `description` _string_ | description contains a free form description of the project. | | MaxLength: 65535
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `enabled` _boolean_ | enabled defines whether a project is enabled or not. Default is true. | | Optional: \{\}
| +| `tags` _[KeystoneTag](#keystonetag) array_ | tags is list of simple strings assigned to a project.
Tags can be used to classify projects into groups. | | MaxItems: 80
MaxLength: 255
MinLength: 1
Optional: \{\}
| #### ProjectResourceStatus @@ -2354,10 +3020,11 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the project. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 65535
| -| `enabled` _boolean_ | enabled represents whether a project is enabled or not. | | | -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 80
items:MaxLength: 1024
| +| `name` _string_ | name is a Human-readable name for the project. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 65535
Optional: \{\}
| +| `domainID` _string_ | domainID is the ID of the Domain to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| +| `enabled` _boolean_ | enabled represents whether a project is enabled or not. | | Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 80
items:MaxLength: 1024
Optional: \{\}
| #### ProjectSpec @@ -2373,11 +3040,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[ProjectImport](#projectimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[ProjectResourceSpec](#projectresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[ProjectImport](#projectimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[ProjectResourceSpec](#projectresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### ProjectStatus @@ -2393,9 +3061,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[ProjectResourceStatus](#projectresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[ProjectResourceStatus](#projectresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### Protocol @@ -2450,9 +3119,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `networkType` _string_ | networkType is the type of physical network that this
network should be mapped to. Supported values are flat, vlan, vxlan, and gre.
Valid values depend on the networking back-end. | | MaxLength: 1024
| -| `physicalNetwork` _string_ | physicalNetwork is the physical network where this network
should be implemented. The Networking API v2.0 does not provide a
way to list available physical networks. For example, the Open
vSwitch plug-in configuration file defines a symbolic name that maps
to specific bridges on each compute host. | | MaxLength: 1024
| -| `segmentationID` _integer_ | segmentationID is the ID of the isolated segment on the
physical network. The network_type attribute defines the
segmentation model. For example, if the network_type value is vlan,
this ID is a vlan identifier. If the network_type value is gre, this
ID is a gre key. | | | +| `networkType` _string_ | networkType is the type of physical network that this
network should be mapped to. Supported values are flat, vlan, vxlan, and gre.
Valid values depend on the networking back-end. | | MaxLength: 1024
Optional: \{\}
| +| `physicalNetwork` _string_ | physicalNetwork is the physical network where this network
should be implemented. The Networking API v2.0 does not provide a
way to list available physical networks. For example, the Open
vSwitch plug-in configuration file defines a symbolic name that maps
to specific bridges on each compute host. | | MaxLength: 1024
Optional: \{\}
| +| `segmentationID` _integer_ | segmentationID is the ID of the isolated segment on the
physical network. The network_type attribute defines the
segmentation model. For example, if the network_type value is vlan,
this ID is a vlan identifier. If the network_type value is gre, this
ID is a gre key. | | Optional: \{\}
| #### Role @@ -2469,170 +3138,176 @@ Role is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Role` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[RoleSpec](#rolespec)_ | spec specifies the desired state of the resource. | | | -| `status` _[RoleStatus](#rolestatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[RoleSpec](#rolespec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[RoleStatus](#rolestatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| -#### RoleFilter +#### RoleAssignment -RoleFilter defines an existing resource by its properties +RoleAssignment is the Schema for an ORC resource. + + -_Validation:_ -- MinProperties: 1 -_Appears in:_ -- [RoleImport](#roleimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
| -| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
| +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `RoleAssignment` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[RoleAssignmentSpec](#roleassignmentspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[RoleAssignmentStatus](#roleassignmentstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| -#### RoleImport +#### RoleAssignmentFilter -RoleImport specifies an existing resource which will be imported instead of -creating a new one +RoleAssignmentFilter defines import filter criteria for existing role assignments. _Validation:_ -- MaxProperties: 1 - MinProperties: 1 _Appears in:_ -- [RoleSpec](#rolespec) +- [RoleAssignmentImport](#roleassignmentimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[RoleFilter](#rolefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `roleRef` _[KubernetesNameRef](#kubernetesnameref)_ | roleRef filters by the referenced Role. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `userRef` _[KubernetesNameRef](#kubernetesnameref)_ | userRef filters by the referenced User. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `groupRef` _[KubernetesNameRef](#kubernetesnameref)_ | groupRef filters by the referenced Group. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef filters by the referenced Project scope. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef filters by the referenced Domain scope. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| -#### RoleResourceSpec - +#### RoleAssignmentImport -RoleResourceSpec contains the desired state of the resource. +RoleAssignmentImport specifies an existing resource which will be imported instead of +creating a new one +_Validation:_ +- MinProperties: 1 _Appears in:_ -- [RoleSpec](#rolespec) +- [RoleAssignmentSpec](#roleassignmentspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
| +| `filter` _[RoleAssignmentFilter](#roleassignmentfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### RoleResourceStatus +#### RoleAssignmentResourceSpec -RoleResourceStatus represents the observed state of the resource. +RoleAssignmentResourceSpec defines the desired role assignment. +A role assignment grants a role to a user or group on a project or domain. +Role assignments are immutable once created and identified by the combination +of (role, actor, scope) rather than a separate ID. _Appears in:_ -- [RoleStatus](#rolestatus) +- [RoleAssignmentSpec](#roleassignmentspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `domainID` _string_ | domainID is the ID of the Domain to which the resource is associated. | | MaxLength: 1024
| +| `roleRef` _[KubernetesNameRef](#kubernetesnameref)_ | roleRef references the Role being assigned. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `userRef` _[KubernetesNameRef](#kubernetesnameref)_ | userRef references the User receiving the role assignment.
Exactly one of userRef or groupRef must be specified. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `groupRef` _[KubernetesNameRef](#kubernetesnameref)_ | groupRef references the Group receiving the role assignment.
Exactly one of userRef or groupRef must be specified. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef references the Project scope for the assignment.
Exactly one of projectRef or domainRef must be specified. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef references the Domain scope for the assignment.
Exactly one of projectRef or domainRef must be specified. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| -#### RoleSpec +#### RoleAssignmentResourceStatus -RoleSpec defines the desired state of an ORC object. +RoleAssignmentResourceStatus represents the observed state of the role assignment. +Note: Role assignments do not have a unique ID in OpenStack - they are identified +by the combination of role, actor (user/group), and scope (project/domain). _Appears in:_ -- [Role](#role) +- [RoleAssignmentStatus](#roleassignmentstatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[RoleImport](#roleimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[RoleResourceSpec](#roleresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `roleID` _string_ | roleID is the OpenStack ID of the assigned role. | | MaxLength: 1024
Optional: \{\}
| +| `userID` _string_ | userID is the OpenStack ID of the user (if actorType is User). | | MaxLength: 1024
Optional: \{\}
| +| `groupID` _string_ | groupID is the OpenStack ID of the group (if actorType is Group). | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the OpenStack ID of the project scope (if scopeType is Project). | | MaxLength: 1024
Optional: \{\}
| +| `domainID` _string_ | domainID is the OpenStack ID of the domain scope (if scopeType is Domain). | | MaxLength: 1024
Optional: \{\}
| -#### RoleStatus +#### RoleAssignmentSpec -RoleStatus defines the observed state of an ORC resource. +RoleAssignmentSpec defines the desired state of an ORC object. _Appears in:_ -- [Role](#role) +- [RoleAssignment](#roleassignment) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[RoleResourceStatus](#roleresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `import` _[RoleAssignmentImport](#roleassignmentimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MinProperties: 1
Optional: \{\}
| +| `resource` _[RoleAssignmentResourceSpec](#roleassignmentresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| -#### Router - +#### RoleAssignmentStatus -Router is the Schema for an ORC resource. +RoleAssignmentStatus defines the observed state of an ORC resource. +_Appears in:_ +- [RoleAssignment](#roleassignment) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | -| `kind` _string_ | `Router` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[RouterSpec](#routerspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[RouterStatus](#routerstatus)_ | status defines the observed state of the resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `resource` _[RoleAssignmentResourceStatus](#roleassignmentresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| -#### RouterFilter +#### RoleFilter -RouterFilter specifies a query to select an OpenStack router. At least one property must be set. +RoleFilter defines an existing resource by its properties _Validation:_ - MinProperties: 1 _Appears in:_ -- [RouterImport](#routerimport) +- [RoleImport](#roleimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `name` _[KeystoneName](#keystonename)_ | name of the existing resource | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| -#### RouterImport +#### RoleImport -RouterImport specifies an existing resource which will be imported instead of +RoleImport specifies an existing resource which will be imported instead of creating a new one _Validation:_ @@ -2640,75 +3315,215 @@ _Validation:_ - MinProperties: 1 _Appears in:_ -- [RouterSpec](#routerspec) +- [RoleSpec](#rolespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[RouterFilter](#routerfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[RoleFilter](#rolefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### RouterInterface - +#### RoleResourceSpec -RouterInterface is the Schema for an ORC resource. +RoleResourceSpec contains the desired state of the resource. +_Appears in:_ +- [RoleSpec](#rolespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | -| `kind` _string_ | `RouterInterface` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[RouterInterfaceSpec](#routerinterfacespec)_ | spec specifies the desired state of the resource. | | | -| `status` _[RouterInterfaceStatus](#routerinterfacestatus)_ | status defines the observed state of the resource. | | | - +| `name` _[KeystoneName](#keystonename)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 64
MinLength: 1
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| -#### RouterInterfaceSpec +#### RoleResourceStatus +RoleResourceStatus represents the observed state of the resource. _Appears in:_ -- [RouterInterface](#routerinterface) +- [RoleStatus](#rolestatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `type` _[RouterInterfaceType](#routerinterfacetype)_ | type specifies the type of the router interface. | | Enum: [Subnet]
MaxLength: 8
MinLength: 1
| -| `routerRef` _[KubernetesNameRef](#kubernetesnameref)_ | routerRef references the router to which this interface belongs. | | MaxLength: 253
MinLength: 1
| -| `subnetRef` _[KubernetesNameRef](#kubernetesnameref)_ | subnetRef references the subnet the router interface is created on. | | MaxLength: 253
MinLength: 1
| - +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `domainID` _string_ | domainID is the ID of the Domain to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| -#### RouterInterfaceStatus +#### RoleSpec +RoleSpec defines the desired state of an ORC object. _Appears in:_ -- [RouterInterface](#routerinterface) +- [Role](#role) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the port created for the router interface | | MaxLength: 1024
| +| `import` _[RoleImport](#roleimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[RoleResourceSpec](#roleresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| -#### RouterInterfaceType +#### RoleStatus -_Underlying type:_ _string_ +RoleStatus defines the observed state of an ORC resource. -_Validation:_ + + +_Appears in:_ +- [Role](#role) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[RoleResourceStatus](#roleresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + +#### Router + + + +Router is the Schema for an ORC resource. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `Router` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[RouterSpec](#routerspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[RouterStatus](#routerstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### RouterFilter + + + +RouterFilter specifies a query to select an OpenStack router. At least one property must be set. + +_Validation:_ +- MinProperties: 1 + +_Appears in:_ +- [RouterImport](#routerimport) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| + + +#### RouterImport + + + +RouterImport specifies an existing resource which will be imported instead of +creating a new one + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [RouterSpec](#routerspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[RouterFilter](#routerfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| + + +#### RouterInterface + + + +RouterInterface is the Schema for an ORC resource. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `RouterInterface` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[RouterInterfaceSpec](#routerinterfacespec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[RouterInterfaceStatus](#routerinterfacestatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### RouterInterfaceSpec + + + + + + + +_Appears in:_ +- [RouterInterface](#routerinterface) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `type` _[RouterInterfaceType](#routerinterfacetype)_ | type specifies the type of the router interface. | | Enum: [Subnet]
MaxLength: 8
MinLength: 1
Required: \{\}
| +| `routerRef` _[KubernetesNameRef](#kubernetesnameref)_ | routerRef references the router to which this interface belongs. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `subnetRef` _[KubernetesNameRef](#kubernetesnameref)_ | subnetRef references the subnet the router interface is created on. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| + + +#### RouterInterfaceStatus + + + + + + + +_Appears in:_ +- [RouterInterface](#routerinterface) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the port created for the router interface | | MaxLength: 1024
Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
of the resource. | | Optional: \{\}
| + + +#### RouterInterfaceType + +_Underlying type:_ _string_ + + + +_Validation:_ - Enum: [Subnet] - MaxLength: 8 - MinLength: 1 @@ -2734,14 +3549,14 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name is a human-readable name of the router. If not set, the
object's name will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the router. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `adminStateUp` _boolean_ | adminStateUp represents the administrative state of the resource,
which is up (true) or down (false). Default is true. | | | -| `externalGateways` _[ExternalGateway](#externalgateway) array_ | externalGateways is a list of external gateways for the router.
Multiple gateways are not currently supported by ORC. | | MaxItems: 1
| -| `distributed` _boolean_ | distributed indicates whether the router is distributed or not. It
is available when dvr extension is enabled. | | | -| `availabilityZoneHints` _[AvailabilityZoneHint](#availabilityzonehint) array_ | availabilityZoneHints is the availability zone candidate for the router. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name is a human-readable name of the router. If not set, the
object's name will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the router. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp represents the administrative state of the resource,
which is up (true) or down (false). Default is true. | | Optional: \{\}
| +| `externalGateways` _[ExternalGateway](#externalgateway) array_ | externalGateways is a list of external gateways for the router.
Multiple gateways are not currently supported by ORC. | | MaxItems: 1
Optional: \{\}
| +| `distributed` _boolean_ | distributed indicates whether the router is distributed or not. It
is available when dvr extension is enabled. | | Optional: \{\}
| +| `availabilityZoneHints` _[AvailabilityZoneHint](#availabilityzonehint) array_ | availabilityZoneHints is the availability zone candidate for the router. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### RouterResourceStatus @@ -2757,14 +3572,14 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is the human-readable name of the resource. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
| -| `status` _string_ | status indicates the current status of the resource. | | MaxLength: 1024
| -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
| -| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the router,
which is up (true) or down (false). | | | -| `externalGateways` _[ExternalGatewayStatus](#externalgatewaystatus) array_ | externalGateways is a list of external gateways for the router. | | MaxItems: 32
| -| `availabilityZoneHints` _string array_ | availabilityZoneHints is the availability zone candidate for the
router. | | MaxItems: 64
items:MaxLength: 1024
| +| `name` _string_ | name is the human-readable name of the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `status` _string_ | status indicates the current status of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the router,
which is up (true) or down (false). | | Optional: \{\}
| +| `externalGateways` _[ExternalGatewayStatus](#externalgatewaystatus) array_ | externalGateways is a list of external gateways for the router. | | MaxItems: 32
Optional: \{\}
| +| `availabilityZoneHints` _string array_ | availabilityZoneHints is the availability zone candidate for the
router. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| #### RouterSpec @@ -2780,11 +3595,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[RouterImport](#routerimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[RouterResourceSpec](#routerresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[RouterImport](#routerimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[RouterResourceSpec](#routerresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### RouterStatus @@ -2800,9 +3616,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[RouterResourceStatus](#routerresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[RouterResourceStatus](#routerresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### RuleDirection @@ -2833,9 +3650,9 @@ SecurityGroup is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `SecurityGroup` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[SecurityGroupSpec](#securitygroupspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[SecurityGroupStatus](#securitygroupstatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[SecurityGroupSpec](#securitygroupspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[SecurityGroupStatus](#securitygroupstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### SecurityGroupFilter @@ -2852,13 +3669,13 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| #### SecurityGroupImport @@ -2877,8 +3694,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[SecurityGroupFilter](#securitygroupfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[SecurityGroupFilter](#securitygroupfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### SecurityGroupResourceSpec @@ -2894,12 +3711,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the security group. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `stateful` _boolean_ | stateful indicates if the security group is stateful or stateless. | | | -| `rules` _[SecurityGroupRule](#securitygrouprule) array_ | rules is a list of security group rules belonging to this SG. | | MaxItems: 256
MinProperties: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the security group. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `stateful` _boolean_ | stateful indicates if the security group is stateful or stateless. | | Optional: \{\}
| +| `rules` _[SecurityGroupRule](#securitygrouprule) array_ | rules is a list of security group rules belonging to this SG. | | MaxItems: 256
MinProperties: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### SecurityGroupResourceStatus @@ -2915,15 +3732,15 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the security group. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `projectID` _string_ | projectID is the project owner of the security group. | | MaxLength: 1024
| -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
| -| `stateful` _boolean_ | stateful indicates if the security group is stateful or stateless. | | | -| `rules` _[SecurityGroupRuleStatus](#securitygrouprulestatus) array_ | rules is a list of security group rules belonging to this SG. | | MaxItems: 256
| -| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | | -| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | | -| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | | +| `name` _string_ | name is a Human-readable name for the security group. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the project owner of the security group. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `stateful` _boolean_ | stateful indicates if the security group is stateful or stateless. | | Optional: \{\}
| +| `rules` _[SecurityGroupRuleStatus](#securitygrouprulestatus) array_ | rules is a list of security group rules belonging to this SG. | | MaxItems: 256
Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
| #### SecurityGroupRule @@ -2940,12 +3757,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `direction` _[RuleDirection](#ruledirection)_ | direction represents the direction in which the security group rule
is applied. Can be ingress or egress. | | Enum: [ingress egress]
| -| `remoteIPPrefix` _[CIDR](#cidr)_ | remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6) | | Format: cidr
MaxLength: 49
MinLength: 1
| -| `protocol` _[Protocol](#protocol)_ | protocol is the IP protocol is represented by a string | | Enum: [ah dccp egp esp gre icmp icmpv6 igmp ipip ipv6-encap ipv6-frag ipv6-icmp ipv6-nonxt ipv6-opts ipv6-route ospf pgm rsvp sctp tcp udp udplite vrrp]
| -| `ethertype` _[Ethertype](#ethertype)_ | ethertype must be IPv4 or IPv6, and addresses represented in CIDR
must match the ingress or egress rules. | | Enum: [IPv4 IPv6]
| -| `portRange` _[PortRangeSpec](#portrangespec)_ | portRange sets the minimum and maximum ports range that the security group rule
matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than
or equal to the PortRange.Max attribute value.
If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max
should be an ICMP type | | | +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `direction` _[RuleDirection](#ruledirection)_ | direction represents the direction in which the security group rule
is applied. Can be ingress or egress. | | Enum: [ingress egress]
Optional: \{\}
| +| `remoteIPPrefix` _[CIDR](#cidr)_ | remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6) | | Format: cidr
MaxLength: 49
MinLength: 1
Optional: \{\}
| +| `protocol` _[Protocol](#protocol)_ | protocol is the IP protocol is represented by a string | | Enum: [ah dccp egp esp gre icmp icmpv6 igmp ipip ipv6-encap ipv6-frag ipv6-icmp ipv6-nonxt ipv6-opts ipv6-route ospf pgm rsvp sctp tcp udp udplite vrrp]
Optional: \{\}
| +| `ethertype` _[Ethertype](#ethertype)_ | ethertype must be IPv4 or IPv6, and addresses represented in CIDR
must match the ingress or egress rules. | | Enum: [IPv4 IPv6]
Required: \{\}
| +| `portRange` _[PortRangeSpec](#portrangespec)_ | portRange sets the minimum and maximum ports range that the security group rule
matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than
or equal to the PortRange.Max attribute value.
If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max
should be an ICMP type | | Optional: \{\}
| #### SecurityGroupRuleStatus @@ -2961,14 +3778,14 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id is the ID of the security group rule. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `direction` _string_ | direction represents the direction in which the security group rule
is applied. Can be ingress or egress. | | MaxLength: 1024
| -| `remoteGroupID` _string_ | remoteGroupID is the remote group UUID to associate with this security group rule
RemoteGroupID | | MaxLength: 1024
| -| `remoteIPPrefix` _string_ | remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6) | | MaxLength: 1024
| -| `protocol` _string_ | protocol is the IP protocol can be represented by a string, an
integer, or null | | MaxLength: 1024
| -| `ethertype` _string_ | ethertype must be IPv4 or IPv6, and addresses represented in CIDR
must match the ingress or egress rules. | | MaxLength: 1024
| -| `portRange` _[PortRangeStatus](#portrangestatus)_ | portRange sets the minimum and maximum ports range that the security group rule
matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than
or equal to the PortRange.Max attribute value.
If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max
should be an ICMP type | | | +| `id` _string_ | id is the ID of the security group rule. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `direction` _string_ | direction represents the direction in which the security group rule
is applied. Can be ingress or egress. | | MaxLength: 1024
Optional: \{\}
| +| `remoteGroupID` _string_ | remoteGroupID is the remote group UUID to associate with this security group rule
RemoteGroupID | | MaxLength: 1024
Optional: \{\}
| +| `remoteIPPrefix` _string_ | remoteIPPrefix is an IP address block. Should match the Ethertype (IPv4 or IPv6) | | MaxLength: 1024
Optional: \{\}
| +| `protocol` _string_ | protocol is the IP protocol can be represented by a string, an
integer, or null | | MaxLength: 1024
Optional: \{\}
| +| `ethertype` _string_ | ethertype must be IPv4 or IPv6, and addresses represented in CIDR
must match the ingress or egress rules. | | MaxLength: 1024
Optional: \{\}
| +| `portRange` _[PortRangeStatus](#portrangestatus)_ | portRange sets the minimum and maximum ports range that the security group rule
matches. If the protocol is [tcp, udp, dccp sctp,udplite] PortRange.Min must be less than
or equal to the PortRange.Max attribute value.
If the protocol is ICMP, this PortRamge.Min must be an ICMP code and PortRange.Max
should be an ICMP type | | Optional: \{\}
| #### SecurityGroupSpec @@ -2984,11 +3801,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[SecurityGroupImport](#securitygroupimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[SecurityGroupResourceSpec](#securitygroupresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[SecurityGroupImport](#securitygroupimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[SecurityGroupResourceSpec](#securitygroupresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### SecurityGroupStatus @@ -3004,16 +3822,539 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[SecurityGroupResourceStatus](#securitygroupresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[SecurityGroupResourceStatus](#securitygroupresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + +#### Server + + + +Server is the Schema for an ORC resource. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `Server` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[ServerSpec](#serverspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[ServerStatus](#serverstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### ServerBootVolumeSpec + + + +ServerBootVolumeSpec defines the boot volume for boot-from-volume server creation. +When specified, the server boots from this volume instead of an image. + + + +_Appears in:_ +- [ServerResourceSpec](#serverresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `volumeRef` _[KubernetesNameRef](#kubernetesnameref)_ | volumeRef is a reference to a Volume object. The volume must be
bootable (created from an image) and available before server creation. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `tag` _string_ | tag is the device tag applied to the volume. | | MaxLength: 255
Optional: \{\}
| + + +#### ServerFilter + + + +ServerFilter defines an existing resource by its properties + +_Validation:_ +- MinProperties: 1 + +_Appears in:_ +- [ServerImport](#serverimport) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `availabilityZone` _string_ | availabilityZone is the availability zone of the existing resource | | MaxLength: 255
Optional: \{\}
| +| `tags` _[ServerTag](#servertag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[ServerTag](#servertag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| +| `notTags` _[ServerTag](#servertag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[ServerTag](#servertag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| + + +#### ServerGroup + + + +ServerGroup is the Schema for an ORC resource. + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `ServerGroup` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[ServerGroupSpec](#servergroupspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[ServerGroupStatus](#servergroupstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### ServerGroupFilter + + + +ServerGroupFilter defines an existing resource by its properties + +_Validation:_ +- MinProperties: 1 + +_Appears in:_ +- [ServerGroupImport](#servergroupimport) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| + + +#### ServerGroupImport + + + +ServerGroupImport specifies an existing resource which will be imported instead of +creating a new one + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [ServerGroupSpec](#servergroupspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[ServerGroupFilter](#servergroupfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| + + +#### ServerGroupPolicy + +_Underlying type:_ _string_ + + + +_Validation:_ +- Enum: [affinity anti-affinity soft-affinity soft-anti-affinity] + +_Appears in:_ +- [ServerGroupResourceSpec](#servergroupresourcespec) + +| Field | Description | +| --- | --- | +| `affinity` | ServerGroupPolicyAffinity is a server group policy that restricts instances belonging to the server group to the same host.
| +| `anti-affinity` | ServerGroupPolicyAntiAffinity is a server group policy that restricts instances belonging to the server group to separate hosts.
| +| `soft-affinity` | ServerGroupPolicySoftAffinity is a server group policy that attempts to restrict instances belonging to the server group to the same host.
Where it is not possible to schedule all instances on one host, they will be scheduled together on as few hosts as possible.
| +| `soft-anti-affinity` | ServerGroupPolicySoftAntiAffinity is a server group policy that attempts to restrict instances belonging to the server group to separate hosts.
Where it is not possible to schedule all instances to separate hosts, they will be scheduled on as many separate hosts as possible.
| + + +#### ServerGroupResourceSpec + + + +ServerGroupResourceSpec contains the desired state of a servergroup + + + +_Appears in:_ +- [ServerGroupSpec](#servergroupspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `policy` _[ServerGroupPolicy](#servergrouppolicy)_ | policy is the policy to use for the server group. | | Enum: [affinity anti-affinity soft-affinity soft-anti-affinity]
Required: \{\}
| +| `rules` _[ServerGroupRules](#servergrouprules)_ | rules is the rules to use for the server group. | | Optional: \{\}
| + + +#### ServerGroupResourceStatus + + + +ServerGroupResourceStatus represents the observed state of the resource. + + + +_Appears in:_ +- [ServerGroupStatus](#servergroupstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is a Human-readable name for the servergroup. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `policy` _string_ | policy is the policy of the servergroup. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
Optional: \{\}
| +| `userID` _string_ | userID of the server group. | | MaxLength: 1024
Optional: \{\}
| +| `rules` _[ServerGroupRulesStatus](#servergrouprulesstatus)_ | rules is the rules of the server group. | | Optional: \{\}
| + + +#### ServerGroupRules + + + + + + + +_Appears in:_ +- [ServerGroupResourceSpec](#servergroupresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `maxServerPerHost` _integer_ | maxServerPerHost specifies how many servers can reside on a single compute host.
It can be used only with the "anti-affinity" policy. | | Optional: \{\}
| + + +#### ServerGroupRulesStatus + + + + + + + +_Appears in:_ +- [ServerGroupResourceStatus](#servergroupresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `maxServerPerHost` _integer_ | maxServerPerHost specifies how many servers can reside on a single compute host.
It can be used only with the "anti-affinity" policy. | | Optional: \{\}
| + + +#### ServerGroupSpec + + + +ServerGroupSpec defines the desired state of an ORC object. + + + +_Appears in:_ +- [ServerGroup](#servergroup) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `import` _[ServerGroupImport](#servergroupimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[ServerGroupResourceSpec](#servergroupresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| + + +#### ServerGroupStatus + + + +ServerGroupStatus defines the observed state of an ORC resource. + + + +_Appears in:_ +- [ServerGroup](#servergroup) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[ServerGroupResourceStatus](#servergroupresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + +#### ServerImport + + + +ServerImport specifies an existing resource which will be imported instead of +creating a new one + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [ServerSpec](#serverspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[ServerFilter](#serverfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| + + +#### ServerInterfaceFixedIP + + + + + + + +_Appears in:_ +- [ServerInterfaceStatus](#serverinterfacestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `ipAddress` _string_ | ipAddress is the IP address assigned to the port. | | MaxLength: 1024
Optional: \{\}
| +| `subnetID` _string_ | subnetID is the ID of the subnet from which the IP address is allocated. | | MaxLength: 1024
Optional: \{\}
| + + +#### ServerInterfaceStatus + + + + + + + +_Appears in:_ +- [ServerResourceStatus](#serverresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `portID` _string_ | portID is the ID of a port attached to the server. | | MaxLength: 1024
Optional: \{\}
| +| `netID` _string_ | netID is the ID of the network to which the interface is attached. | | MaxLength: 1024
Optional: \{\}
| +| `macAddr` _string_ | macAddr is the MAC address of the interface. | | MaxLength: 1024
Optional: \{\}
| +| `portState` _string_ | portState is the state of the port (e.g., ACTIVE, DOWN). | | MaxLength: 1024
Optional: \{\}
| +| `fixedIPs` _[ServerInterfaceFixedIP](#serverinterfacefixedip) array_ | fixedIPs is the list of fixed IP addresses assigned to the interface. | | MaxItems: 32
Optional: \{\}
| + + +#### ServerMetadata + + + +ServerMetadata represents a key-value pair for server metadata. + + + +_Appears in:_ +- [ServerResourceSpec](#serverresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `key` _string_ | key is the metadata key. | | MaxLength: 255
MinLength: 1
Required: \{\}
| +| `value` _string_ | value is the metadata value. | | MaxLength: 255
MinLength: 1
Required: \{\}
| + + +#### ServerMetadataStatus + + + +ServerMetadataStatus represents a key-value pair for server metadata in status. + + + +_Appears in:_ +- [ServerResourceStatus](#serverresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `key` _string_ | key is the metadata key. | | MaxLength: 255
Optional: \{\}
| +| `value` _string_ | value is the metadata value. | | MaxLength: 255
Optional: \{\}
| + + +#### ServerPortSpec + + + + + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [ServerResourceSpec](#serverresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to a Port object. Server creation will wait for
this port to be created and available. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| + + +#### ServerResourceSpec + + + +ServerResourceSpec contains the desired state of a server + + + +_Appears in:_ +- [ServerSpec](#serverspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `imageRef` _[KubernetesNameRef](#kubernetesnameref)_ | imageRef references the image to use for the server instance.
This field is required unless bootVolume is specified for boot-from-volume. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `flavorRef` _[KubernetesNameRef](#kubernetesnameref)_ | flavorRef references the flavor to use for the server instance. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `bootVolume` _[ServerBootVolumeSpec](#serverbootvolumespec)_ | bootVolume specifies a volume to boot from instead of an image.
When specified, imageRef must be omitted. The volume must be
bootable (created from an image using imageRef in the Volume spec). | | Optional: \{\}
| +| `userData` _[UserDataSpec](#userdataspec)_ | userData specifies data which will be made available to the server at
boot time, either via the metadata service or a config drive. It is
typically read by a configuration service such as cloud-init or ignition. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `ports` _[ServerPortSpec](#serverportspec) array_ | ports defines a list of ports which will be attached to the server. | | MaxItems: 64
MaxProperties: 1
MinProperties: 1
Required: \{\}
| +| `volumes` _[ServerVolumeSpec](#servervolumespec) array_ | volumes is a list of volumes attached to the server. | | MaxItems: 64
MinProperties: 1
Optional: \{\}
| +| `availabilityZone` _string_ | availabilityZone is the availability zone in which to create the server. | | MaxLength: 255
Optional: \{\}
| +| `keypairRef` _[KubernetesNameRef](#kubernetesnameref)_ | keypairRef is a reference to a KeyPair object. The server will be
created with this keypair for SSH access. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `tags` _[ServerTag](#servertag) array_ | tags is a list of tags which will be applied to the server. | | MaxItems: 50
MaxLength: 80
MinLength: 1
Optional: \{\}
| +| `metadata` _[ServerMetadata](#servermetadata) array_ | Refer to Kubernetes API documentation for fields of `metadata`. | | MaxItems: 128
Optional: \{\}
| +| `configDrive` _boolean_ | configDrive specifies whether to attach a config drive to the server.
When true, configuration data will be available via a special drive
instead of the metadata service. | | Optional: \{\}
| +| `schedulerHints` _[ServerSchedulerHints](#serverschedulerhints)_ | schedulerHints provides hints to the Nova scheduler for server placement. | | Optional: \{\}
| + + +#### ServerResourceStatus + + + +ServerResourceStatus represents the observed state of the resource. + + + +_Appears in:_ +- [ServerStatus](#serverstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is the human-readable name of the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `hostID` _string_ | hostID is the host where the server is located in the cloud. | | MaxLength: 1024
Optional: \{\}
| +| `status` _string_ | status contains the current operational status of the server,
such as IN_PROGRESS or ACTIVE. | | MaxLength: 1024
Optional: \{\}
| +| `imageID` _string_ | imageID indicates the OS image used to deploy the server. | | MaxLength: 1024
Optional: \{\}
| +| `availabilityZone` _string_ | availabilityZone is the availability zone where the server is located. | | MaxLength: 1024
Optional: \{\}
| +| `serverGroups` _string array_ | serverGroups is a slice of strings containing the UUIDs of the
server groups to which the server belongs. Currently this can
contain at most one entry. | | MaxItems: 32
items:MaxLength: 1024
Optional: \{\}
| +| `volumes` _[ServerVolumeStatus](#servervolumestatus) array_ | volumes contains the volumes attached to the server. | | MaxItems: 64
Optional: \{\}
| +| `interfaces` _[ServerInterfaceStatus](#serverinterfacestatus) array_ | interfaces contains the list of interfaces attached to the server. | | MaxItems: 64
Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 50
items:MaxLength: 1024
Optional: \{\}
| +| `metadata` _[ServerMetadataStatus](#servermetadatastatus) array_ | Refer to Kubernetes API documentation for fields of `metadata`. | | MaxItems: 128
Optional: \{\}
| +| `configDrive` _boolean_ | configDrive indicates whether the server was booted with a config drive. | | Optional: \{\}
| + + +#### ServerSchedulerHints + + + +ServerSchedulerHints provides hints to the Nova scheduler for server placement. + + + +_Appears in:_ +- [ServerResourceSpec](#serverresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `serverGroupRef` _[KubernetesNameRef](#kubernetesnameref)_ | serverGroupRef is a reference to a ServerGroup object. The server will be
scheduled on a host in the specified server group. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `differentHostServerRefs` _[KubernetesNameRef](#kubernetesnameref) array_ | differentHostServerRefs is a list of references to Server objects.
The server will be scheduled on a different host than all specified servers. | | MaxItems: 64
MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `sameHostServerRefs` _[KubernetesNameRef](#kubernetesnameref) array_ | sameHostServerRefs is a list of references to Server objects.
The server will be scheduled on the same host as all specified servers. | | MaxItems: 64
MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `query` _string_ | query is a conditional statement that results in compute nodes
able to host the server. | | MaxLength: 1024
Optional: \{\}
| +| `targetCell` _string_ | targetCell is a cell name where the server will be placed. | | MaxLength: 255
Optional: \{\}
| +| `differentCell` _string array_ | differentCell is a list of cell names where the server should not
be placed. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `buildNearHostIP` _[CIDR](#cidr)_ | buildNearHostIP specifies a subnet of compute nodes to host the server.
The host IP should be provided in an CIDR format like 10.10.10.10/24. | | Format: cidr
MaxLength: 49
MinLength: 1
Optional: \{\}
| +| `additionalProperties` _object (keys:string, values:string)_ | additionalProperties is a map of arbitrary key/value pairs that are
not validated by Nova. | | Optional: \{\}
| + + +#### ServerSpec + + + +ServerSpec defines the desired state of an ORC object. + + + +_Appears in:_ +- [Server](#server) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `import` _[ServerImport](#serverimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[ServerResourceSpec](#serverresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| + + +#### ServerStatus + + + +ServerStatus defines the observed state of an ORC resource. + + + +_Appears in:_ +- [Server](#server) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[ServerResourceStatus](#serverresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + +#### ServerTag + +_Underlying type:_ _string_ + + + +_Validation:_ +- MaxLength: 80 +- MinLength: 1 + +_Appears in:_ +- [FilterByServerTags](#filterbyservertags) +- [ServerFilter](#serverfilter) +- [ServerResourceSpec](#serverresourcespec) + + + +#### ServerVolumeSpec + + + + + +_Validation:_ +- MinProperties: 1 + +_Appears in:_ +- [ServerResourceSpec](#serverresourcespec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `volumeRef` _[KubernetesNameRef](#kubernetesnameref)_ | volumeRef is a reference to a Volume object. Server creation will wait for
this volume to be created and available. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `device` _string_ | device is the name of the device, such as `/dev/vdb`.
Omit for auto-assignment | | MaxLength: 255
Optional: \{\}
| + + +#### ServerVolumeStatus + + + + + + + +_Appears in:_ +- [ServerResourceStatus](#serverresourcestatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id is the ID of a volume attached to the server. | | MaxLength: 1024
Optional: \{\}
| -#### Server +#### Service -Server is the Schema for an ORC resource. +Service is the Schema for an ORC resource. @@ -3022,436 +4363,476 @@ Server is the Schema for an ORC resource. | Field | Description | Default | Validation | | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | -| `kind` _string_ | `Server` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[ServerSpec](#serverspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[ServerStatus](#serverstatus)_ | status defines the observed state of the resource. | | | +| `kind` _string_ | `Service` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[ServiceSpec](#servicespec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[ServiceStatus](#servicestatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| -#### ServerFilter +#### ServiceFilter -ServerFilter defines an existing resource by its properties +ServiceFilter defines an existing resource by its properties _Validation:_ - MinProperties: 1 _Appears in:_ -- [ServerImport](#serverimport) +- [ServiceImport](#serviceimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `availabilityZone` _string_ | availabilityZone is the availability zone of the existing resource | | MaxLength: 255
| -| `tags` _[ServerTag](#servertag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| -| `tagsAny` _[ServerTag](#servertag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| -| `notTags` _[ServerTag](#servertag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| -| `notTagsAny` _[ServerTag](#servertag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| - - -#### ServerGroup +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `type` _string_ | type of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +#### ServiceImport -ServerGroup is the Schema for an ORC resource. +ServiceImport specifies an existing resource which will be imported instead of +creating a new one +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 +_Appears in:_ +- [ServiceSpec](#servicespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | -| `kind` _string_ | `ServerGroup` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[ServerGroupSpec](#servergroupspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[ServerGroupStatus](#servergroupstatus)_ | status defines the observed state of the resource. | | | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[ServiceFilter](#servicefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### ServerGroupFilter +#### ServiceResourceSpec -ServerGroupFilter defines an existing resource by its properties +ServiceResourceSpec contains the desired state of the resource. + -_Validation:_ -- MinProperties: 1 _Appears in:_ -- [ServerGroupImport](#servergroupimport) +- [ServiceSpec](#servicespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| +| `name` _[OpenStackName](#openstackname)_ | name indicates the name of service. If not specified, the name of the ORC
resource will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description indicates the description of service. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `type` _string_ | type indicates which resource the service is responsible for. | | MaxLength: 255
MinLength: 1
Required: \{\}
| +| `enabled` _boolean_ | enabled indicates whether the service is enabled or not. | true | Optional: \{\}
| -#### ServerGroupImport +#### ServiceResourceStatus -ServerGroupImport specifies an existing resource which will be imported instead of -creating a new one +ServiceResourceStatus represents the observed state of the resource. + -_Validation:_ -- MaxProperties: 1 -- MinProperties: 1 _Appears in:_ -- [ServerGroupSpec](#servergroupspec) +- [ServiceStatus](#servicestatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[ServerGroupFilter](#servergroupfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `name` _string_ | name indicates the name of service. | | MaxLength: 255
Optional: \{\}
| +| `description` _string_ | description indicates the description of service. | | MaxLength: 255
Optional: \{\}
| +| `type` _string_ | type indicates which resource the service is responsible for. | | MaxLength: 255
Optional: \{\}
| +| `enabled` _boolean_ | enabled indicates whether the service is enabled or not. | | Optional: \{\}
| -#### ServerGroupPolicy +#### ServiceSpec -_Underlying type:_ _string_ +ServiceSpec defines the desired state of an ORC object. + -_Validation:_ -- Enum: [affinity anti-affinity soft-affinity soft-anti-affinity] _Appears in:_ -- [ServerGroupResourceSpec](#servergroupresourcespec) +- [Service](#service) -| Field | Description | -| --- | --- | -| `affinity` | ServerGroupPolicyAffinity is a server group policy that restricts instances belonging to the server group to the same host.
| -| `anti-affinity` | ServerGroupPolicyAntiAffinity is a server group policy that restricts instances belonging to the server group to separate hosts.
| -| `soft-affinity` | ServerGroupPolicySoftAffinity is a server group policy that attempts to restrict instances belonging to the server group to the same host.
Where it is not possible to schedule all instances on one host, they will be scheduled together on as few hosts as possible.
| -| `soft-anti-affinity` | ServerGroupPolicySoftAntiAffinity is a server group policy that attempts to restrict instances belonging to the server group to separate hosts.
Where it is not possible to schedule all instances to separate hosts, they will be scheduled on as many separate hosts as possible.
| +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `import` _[ServiceImport](#serviceimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[ServiceResourceSpec](#serviceresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| -#### ServerGroupResourceSpec +#### ServiceStatus -ServerGroupResourceSpec contains the desired state of a servergroup +ServiceStatus defines the observed state of an ORC resource. _Appears in:_ -- [ServerGroupSpec](#servergroupspec) +- [Service](#service) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `policy` _[ServerGroupPolicy](#servergrouppolicy)_ | policy is the policy to use for the server group. | | Enum: [affinity anti-affinity soft-affinity soft-anti-affinity]
| -| `rules` _[ServerGroupRules](#servergrouprules)_ | rules is the rules to use for the server group. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[ServiceResourceStatus](#serviceresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| -#### ServerGroupResourceStatus +#### ShareNetwork -ServerGroupResourceStatus represents the observed state of the resource. +ShareNetwork is the Schema for an ORC resource. + -_Appears in:_ -- [ServerGroupStatus](#servergroupstatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the servergroup. Might not be unique. | | MaxLength: 1024
| -| `policy` _string_ | policy is the policy of the servergroup. | | MaxLength: 1024
| -| `projectID` _string_ | projectID is the project owner of the resource. | | MaxLength: 1024
| -| `userID` _string_ | userID of the server group. | | MaxLength: 1024
| -| `rules` _[ServerGroupRulesStatus](#servergrouprulesstatus)_ | rules is the rules of the server group. | | | - - -#### ServerGroupRules +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `ShareNetwork` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[ShareNetworkSpec](#sharenetworkspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[ShareNetworkStatus](#sharenetworkstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| +#### ShareNetworkFilter +ShareNetworkFilter defines an existing resource by its properties +_Validation:_ +- MinProperties: 1 _Appears in:_ -- [ServerGroupResourceSpec](#servergroupresourcespec) +- [ShareNetworkImport](#sharenetworkimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `maxServerPerHost` _integer_ | maxServerPerHost specifies how many servers can reside on a single compute host.
It can be used only with the "anti-affinity" policy. | | | - - -#### ServerGroupRulesStatus +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +#### ShareNetworkImport +ShareNetworkImport specifies an existing resource which will be imported instead of +creating a new one +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 _Appears in:_ -- [ServerGroupResourceStatus](#servergroupresourcestatus) +- [ShareNetworkSpec](#sharenetworkspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `maxServerPerHost` _integer_ | maxServerPerHost specifies how many servers can reside on a single compute host.
It can be used only with the "anti-affinity" policy. | | | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[ShareNetworkFilter](#sharenetworkfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### ServerGroupSpec +#### ShareNetworkResourceSpec -ServerGroupSpec defines the desired state of an ORC object. +ShareNetworkResourceSpec contains the desired state of the resource. _Appears in:_ -- [ServerGroup](#servergroup) +- [ShareNetworkSpec](#sharenetworkspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[ServerGroupImport](#servergroupimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[ServerGroupResourceSpec](#servergroupresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `subnetRef` _[KubernetesNameRef](#kubernetesnameref)_ | subnetRef is a reference to the ORC Subnet which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| -#### ServerGroupStatus +#### ShareNetworkResourceStatus -ServerGroupStatus defines the observed state of an ORC resource. +ShareNetworkResourceStatus represents the observed state of the resource. _Appears in:_ -- [ServerGroup](#servergroup) +- [ShareNetworkStatus](#sharenetworkstatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[ServerGroupResourceStatus](#servergroupresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `name` _string_ | name is a Human-readable name for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `neutronNetID` _string_ | neutronNetID is the Neutron network ID. | | MaxLength: 1024
Optional: \{\}
| +| `neutronSubnetID` _string_ | neutronSubnetID is the Neutron subnet ID. | | MaxLength: 1024
Optional: \{\}
| +| `networkType` _string_ | networkType is the network type (e.g., vlan, vxlan, flat). | | MaxLength: 1024
Optional: \{\}
| +| `segmentationID` _integer_ | segmentationID is the segmentation ID of the network. | | Optional: \{\}
| +| `cidr` _string_ | cidr is the CIDR of the subnet. | | MaxLength: 1024
Optional: \{\}
| +| `ipVersion` _integer_ | ipVersion is the IP version (4 or 6). | | Optional: \{\}
| +| `projectID` _string_ | projectID is the ID of the project that owns the share network. | | MaxLength: 1024
Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. | | Optional: \{\}
| -#### ServerImport +#### ShareNetworkSpec -ServerImport specifies an existing resource which will be imported instead of -creating a new one +ShareNetworkSpec defines the desired state of an ORC object. + -_Validation:_ -- MaxProperties: 1 -- MinProperties: 1 _Appears in:_ -- [ServerSpec](#serverspec) +- [ShareNetwork](#sharenetwork) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[ServerFilter](#serverfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| - +| `import` _[ShareNetworkImport](#sharenetworkimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[ShareNetworkResourceSpec](#sharenetworkresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| -#### ServerInterfaceFixedIP +#### ShareNetworkStatus +ShareNetworkStatus defines the observed state of an ORC resource. _Appears in:_ -- [ServerInterfaceStatus](#serverinterfacestatus) +- [ShareNetwork](#sharenetwork) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `ipAddress` _string_ | ipAddress is the IP address assigned to the port. | | MaxLength: 1024
| -| `subnetID` _string_ | subnetID is the ID of the subnet from which the IP address is allocated. | | MaxLength: 1024
| +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[ShareNetworkResourceStatus](#sharenetworkresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| -#### ServerInterfaceStatus +#### Subnet +Subnet is the Schema for an ORC resource. -_Appears in:_ -- [ServerResourceStatus](#serverresourcestatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `portID` _string_ | portID is the ID of a port attached to the server. | | MaxLength: 1024
| -| `netID` _string_ | netID is the ID of the network to which the interface is attached. | | MaxLength: 1024
| -| `macAddr` _string_ | macAddr is the MAC address of the interface. | | MaxLength: 1024
| -| `portState` _string_ | portState is the state of the port (e.g., ACTIVE, DOWN). | | MaxLength: 1024
| -| `fixedIPs` _[ServerInterfaceFixedIP](#serverinterfacefixedip) array_ | fixedIPs is the list of fixed IP addresses assigned to the interface. | | MaxItems: 32
| - +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `Subnet` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[SubnetSpec](#subnetspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[SubnetStatus](#subnetstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| -#### ServerPortSpec +#### SubnetFilter +SubnetFilter specifies a filter to select a subnet. At least one parameter must be specified. _Validation:_ -- MaxProperties: 1 - MinProperties: 1 _Appears in:_ -- [ServerResourceSpec](#serverresourcespec) +- [SubnetImport](#subnetimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to a Port object. Server creation will wait for
this port to be created and available. | | MaxLength: 253
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `ipVersion` _[IPVersion](#ipversion)_ | ipVersion of the existing resource | | Enum: [4 6]
Optional: \{\}
| +| `gatewayIP` _[IPvAny](#ipvany)_ | gatewayIP is the IP address of the gateway of the existing resource | | MaxLength: 45
MinLength: 1
Optional: \{\}
| +| `cidr` _[CIDR](#cidr)_ | cidr of the existing resource | | Format: cidr
MaxLength: 49
MinLength: 1
Optional: \{\}
| +| `ipv6` _[IPv6Options](#ipv6options)_ | ipv6 options of the existing resource | | MinProperties: 1
Optional: \{\}
| +| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this subnet is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| -#### ServerResourceSpec +#### SubnetGateway + -ServerResourceSpec contains the desired state of a server _Appears in:_ -- [ServerSpec](#serverspec) +- [SubnetResourceSpec](#subnetresourcespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `imageRef` _[KubernetesNameRef](#kubernetesnameref)_ | imageRef references the image to use for the server instance.
NOTE: This is not required in case of boot from volume. | | MaxLength: 253
MinLength: 1
| -| `flavorRef` _[KubernetesNameRef](#kubernetesnameref)_ | flavorRef references the flavor to use for the server instance. | | MaxLength: 253
MinLength: 1
| -| `userData` _[UserDataSpec](#userdataspec)_ | userData specifies data which will be made available to the server at
boot time, either via the metadata service or a config drive. It is
typically read by a configuration service such as cloud-init or ignition. | | MaxProperties: 1
MinProperties: 1
| -| `ports` _[ServerPortSpec](#serverportspec) array_ | ports defines a list of ports which will be attached to the server. | | MaxItems: 64
MaxProperties: 1
MinProperties: 1
| -| `volumes` _[ServerVolumeSpec](#servervolumespec) array_ | volumes is a list of volumes attached to the server. | | MaxItems: 64
MinProperties: 1
| -| `serverGroupRef` _[KubernetesNameRef](#kubernetesnameref)_ | serverGroupRef is a reference to a ServerGroup object. The server
will be created in the server group. | | MaxLength: 253
MinLength: 1
| -| `availabilityZone` _string_ | availabilityZone is the availability zone in which to create the server. | | MaxLength: 255
| -| `keypairRef` _[KubernetesNameRef](#kubernetesnameref)_ | keypairRef is a reference to a KeyPair object. The server will be
created with this keypair for SSH access. | | MaxLength: 253
MinLength: 1
| -| `tags` _[ServerTag](#servertag) array_ | tags is a list of tags which will be applied to the server. | | MaxItems: 50
MaxLength: 80
MinLength: 1
| +| `type` _[SubnetGatewayType](#subnetgatewaytype)_ | type specifies how the default gateway will be created. `Automatic`
specifies that neutron will automatically add a default gateway. This is
also the default if no Gateway is specified. `None` specifies that the
subnet will not have a default gateway. `IP` specifies that the subnet
will use a specific address as the default gateway, which must be
specified in `IP`. | | Enum: [None Automatic IP]
Required: \{\}
| +| `ip` _[IPvAny](#ipvany)_ | ip is the IP address of the default gateway, which must be specified if
Type is `IP`. It must be a valid IP address, either IPv4 or IPv6,
matching the IPVersion in SubnetResourceSpec. | | MaxLength: 45
MinLength: 1
Optional: \{\}
| -#### ServerResourceStatus +#### SubnetGatewayType +_Underlying type:_ _string_ -ServerResourceStatus represents the observed state of the resource. _Appears in:_ -- [ServerStatus](#serverstatus) - -| Field | Description | Default | Validation | -| --- | --- | --- | --- | -| `name` _string_ | name is the human-readable name of the resource. Might not be unique. | | MaxLength: 1024
| -| `hostID` _string_ | hostID is the host where the server is located in the cloud. | | MaxLength: 1024
| -| `status` _string_ | status contains the current operational status of the server,
such as IN_PROGRESS or ACTIVE. | | MaxLength: 1024
| -| `imageID` _string_ | imageID indicates the OS image used to deploy the server. | | MaxLength: 1024
| -| `availabilityZone` _string_ | availabilityZone is the availability zone where the server is located. | | MaxLength: 1024
| -| `serverGroups` _string array_ | serverGroups is a slice of strings containing the UUIDs of the
server groups to which the server belongs. Currently this can
contain at most one entry. | | MaxItems: 32
items:MaxLength: 1024
| -| `volumes` _[ServerVolumeStatus](#servervolumestatus) array_ | volumes contains the volumes attached to the server. | | MaxItems: 64
| -| `interfaces` _[ServerInterfaceStatus](#serverinterfacestatus) array_ | interfaces contains the list of interfaces attached to the server. | | MaxItems: 64
| -| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 50
items:MaxLength: 1024
| +- [SubnetGateway](#subnetgateway) -#### ServerSpec +#### SubnetImport -ServerSpec defines the desired state of an ORC object. +SubnetImport specifies an existing resource which will be imported instead of +creating a new one +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 _Appears in:_ -- [Server](#server) +- [SubnetSpec](#subnetspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[ServerImport](#serverimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[ServerResourceSpec](#serverresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[SubnetFilter](#subnetfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### ServerStatus +#### SubnetResourceSpec + -ServerStatus defines the observed state of an ORC resource. _Appears in:_ -- [Server](#server) +- [SubnetSpec](#subnetspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[ServerResourceStatus](#serverresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `name` _[OpenStackName](#openstackname)_ | name is a human-readable name of the subnet. If not set, the object's name will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this subnet is associated with. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the subnet. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `ipVersion` _[IPVersion](#ipversion)_ | ipVersion is the IP version for the subnet. | | Enum: [4 6]
Required: \{\}
| +| `cidr` _[CIDR](#cidr)_ | cidr is the address CIDR of the subnet. It must match the IP version specified in IPVersion. | | Format: cidr
MaxLength: 49
MinLength: 1
Required: \{\}
| +| `allocationPools` _[AllocationPool](#allocationpool) array_ | allocationPools are IP Address pools that will be available for DHCP. IP
addresses must be in CIDR. | | MaxItems: 32
Optional: \{\}
| +| `gateway` _[SubnetGateway](#subnetgateway)_ | gateway specifies the default gateway of the subnet. If not specified,
neutron will add one automatically. To disable this behaviour, specify a
gateway with a type of None. | | Optional: \{\}
| +| `enableDHCP` _boolean_ | enableDHCP will either enable to disable the DHCP service. | | Optional: \{\}
| +| `dnsNameservers` _[IPvAny](#ipvany) array_ | dnsNameservers are the nameservers to be set via DHCP. | | MaxItems: 16
MaxLength: 45
MinLength: 1
Optional: \{\}
| +| `dnsPublishFixedIP` _boolean_ | dnsPublishFixedIP will either enable or disable the publication of
fixed IPs to the DNS. Defaults to false. | | Optional: \{\}
| +| `hostRoutes` _[HostRoute](#hostroute) array_ | hostRoutes are any static host routes to be set via DHCP. | | MaxItems: 256
Optional: \{\}
| +| `ipv6` _[IPv6Options](#ipv6options)_ | ipv6 contains IPv6-specific options. It may only be set if IPVersion is 6. | | MinProperties: 1
Optional: \{\}
| +| `routerRef` _[KubernetesNameRef](#kubernetesnameref)_ | routerRef specifies a router to attach the subnet to | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| + + +#### SubnetResourceStatus -#### ServerTag -_Underlying type:_ _string_ -_Validation:_ -- MaxLength: 80 -- MinLength: 1 _Appears in:_ -- [FilterByServerTags](#filterbyservertags) -- [ServerFilter](#serverfilter) -- [ServerResourceSpec](#serverresourcespec) +- [SubnetStatus](#subnetstatus) +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is the human-readable name of the subnet. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `ipVersion` _integer_ | ipVersion specifies IP version, either `4' or `6'. | | Optional: \{\}
| +| `cidr` _string_ | cidr representing IP range for this subnet, based on IP version. | | MaxLength: 1024
Optional: \{\}
| +| `gatewayIP` _string_ | gatewayIP is the default gateway used by devices in this subnet, if any. | | MaxLength: 1024
Optional: \{\}
| +| `dnsNameservers` _string array_ | dnsNameservers is a list of name servers used by hosts in this subnet. | | MaxItems: 16
items:MaxLength: 1024
Optional: \{\}
| +| `dnsPublishFixedIP` _boolean_ | dnsPublishFixedIP specifies whether the fixed IP addresses are published to the DNS. | | Optional: \{\}
| +| `allocationPools` _[AllocationPoolStatus](#allocationpoolstatus) array_ | allocationPools is a list of sub-ranges within CIDR available for dynamic
allocation to ports. | | MaxItems: 32
Optional: \{\}
| +| `hostRoutes` _[HostRouteStatus](#hostroutestatus) array_ | hostRoutes is a list of routes that should be used by devices with IPs
from this subnet (not including local subnet route). | | MaxItems: 256
Optional: \{\}
| +| `enableDHCP` _boolean_ | enableDHCP specifies whether DHCP is enabled for this subnet or not. | | Optional: \{\}
| +| `networkID` _string_ | networkID is the ID of the network to which the subnet belongs. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the project owner of the subnet. | | MaxLength: 1024
Optional: \{\}
| +| `ipv6AddressMode` _string_ | ipv6AddressMode specifies mechanisms for assigning IPv6 IP addresses. | | MaxLength: 1024
Optional: \{\}
| +| `ipv6RAMode` _string_ | ipv6RAMode is the IPv6 router advertisement mode. It specifies
whether the networking service should transmit ICMPv6 packets. | | MaxLength: 1024
Optional: \{\}
| +| `subnetPoolID` _string_ | subnetPoolID is the id of the subnet pool associated with the subnet. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _string array_ | tags optionally set via extensions/attributestags | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
| -#### ServerVolumeSpec +#### SubnetSpec +SubnetSpec defines the desired state of an ORC object. -_Validation:_ -- MinProperties: 1 _Appears in:_ -- [ServerResourceSpec](#serverresourcespec) +- [Subnet](#subnet) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `volumeRef` _[KubernetesNameRef](#kubernetesnameref)_ | volumeRef is a reference to a Volume object. Server creation will wait for
this volume to be created and available. | | MaxLength: 253
MinLength: 1
| -| `device` _string_ | device is the name of the device, such as `/dev/vdb`.
Omit for auto-assignment | | MaxLength: 255
| +| `import` _[SubnetImport](#subnetimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[SubnetResourceSpec](#subnetresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| -#### ServerVolumeStatus - +#### SubnetStatus +SubnetStatus defines the observed state of an ORC resource. _Appears in:_ -- [ServerResourceStatus](#serverresourcestatus) +- [Subnet](#subnet) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id is the ID of a volume attached to the server. | | MaxLength: 1024
| +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[SubnetResourceStatus](#subnetresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| -#### Service +#### Trunk -Service is the Schema for an ORC resource. +Trunk is the Schema for an ORC resource. @@ -3460,35 +4841,42 @@ Service is the Schema for an ORC resource. | Field | Description | Default | Validation | | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | -| `kind` _string_ | `Service` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[ServiceSpec](#servicespec)_ | spec specifies the desired state of the resource. | | | -| `status` _[ServiceStatus](#servicestatus)_ | status defines the observed state of the resource. | | | +| `kind` _string_ | `Trunk` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[TrunkSpec](#trunkspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[TrunkStatus](#trunkstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| -#### ServiceFilter +#### TrunkFilter -ServiceFilter defines an existing resource by its properties +TrunkFilter defines an existing resource by its properties _Validation:_ - MinProperties: 1 _Appears in:_ -- [ServiceImport](#serviceimport) +- [TrunkImport](#trunkimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `type` _string_ | type of the existing resource | | MaxLength: 255
MinLength: 1
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to the ORC Port which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the trunk. | | Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| -#### ServiceImport +#### TrunkImport -ServiceImport specifies an existing resource which will be imported instead of +TrunkImport specifies an existing resource which will be imported instead of creating a new one _Validation:_ @@ -3496,307 +4884,299 @@ _Validation:_ - MinProperties: 1 _Appears in:_ -- [ServiceSpec](#servicespec) +- [TrunkSpec](#trunkspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[ServiceFilter](#servicefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[TrunkFilter](#trunkfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### ServiceResourceSpec +#### TrunkResourceSpec -ServiceResourceSpec contains the desired state of the resource. +TrunkResourceSpec contains the desired state of the resource. _Appears in:_ -- [ServiceSpec](#servicespec) +- [TrunkSpec](#trunkspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name indicates the name of service. If not specified, the name of the ORC
resource will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _string_ | description indicates the description of service. | | MaxLength: 255
MinLength: 1
| -| `type` _string_ | type indicates which resource the service is responsible for. | | MaxLength: 255
MinLength: 1
| -| `enabled` _boolean_ | enabled indicates whether the service is enabled or not. | true | | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to the ORC Port which this resource is associated with. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the trunk. If false (down),
the trunk does not forward packets. | | Optional: \{\}
| +| `subports` _[TrunkSubportSpec](#trunksubportspec) array_ | subports is the list of ports to attach to the trunk. | | MaxItems: 1024
Optional: \{\}
| +| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of Neutron tags to apply to the trunk. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
| -#### ServiceResourceStatus +#### TrunkResourceStatus -ServiceResourceStatus represents the observed state of the resource. +TrunkResourceStatus represents the observed state of the resource. _Appears in:_ -- [ServiceStatus](#servicestatus) +- [TrunkStatus](#trunkstatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name indicates the name of service. | | MaxLength: 255
| -| `description` _string_ | description indicates the description of service. | | MaxLength: 255
| -| `type` _string_ | type indicates which resource the service is responsible for. | | MaxLength: 255
| -| `enabled` _boolean_ | enabled indicates whether the service is enabled or not. | | | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `portID` _string_ | portID is the ID of the Port to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| +| `projectID` _string_ | projectID is the ID of the Project to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| +| `tenantID` _string_ | tenantID is the project owner of the trunk (alias of projectID in some deployments). | | MaxLength: 1024
Optional: \{\}
| +| `status` _string_ | status indicates whether the trunk is currently operational. | | MaxLength: 1024
Optional: \{\}
| +| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
| +| `adminStateUp` _boolean_ | adminStateUp is the administrative state of the trunk. | | Optional: \{\}
| +| `subports` _[TrunkSubportStatus](#trunksubportstatus) array_ | subports is a list of ports associated with the trunk. | | MaxItems: 1024
Optional: \{\}
| -#### ServiceSpec +#### TrunkSpec -ServiceSpec defines the desired state of an ORC object. +TrunkSpec defines the desired state of an ORC object. _Appears in:_ -- [Service](#service) +- [Trunk](#trunk) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[ServiceImport](#serviceimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[ServiceResourceSpec](#serviceresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[TrunkImport](#trunkimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[TrunkResourceSpec](#trunkresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| -#### ServiceStatus +#### TrunkStatus -ServiceStatus defines the observed state of an ORC resource. +TrunkStatus defines the observed state of an ORC resource. _Appears in:_ -- [Service](#service) +- [Trunk](#trunk) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[ServiceResourceStatus](#serviceresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | - +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[TrunkResourceStatus](#trunkresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| -#### Subnet +#### TrunkSubportSpec -Subnet is the Schema for an ORC resource. +TrunkSubportSpec represents a subport to attach to a trunk. +It maps to gophercloud's trunks.Subport. +_Appears in:_ +- [TrunkResourceSpec](#trunkresourcespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | -| `kind` _string_ | `Subnet` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[SubnetSpec](#subnetspec)_ | spec specifies the desired state of the resource. | | | -| `status` _[SubnetStatus](#subnetstatus)_ | status defines the observed state of the resource. | | | +| `portRef` _[KubernetesNameRef](#kubernetesnameref)_ | portRef is a reference to the ORC Port that will be attached as a subport. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `segmentationID` _integer_ | segmentationID is the segmentation ID for the subport (e.g. VLAN ID). | | Maximum: 4094
Minimum: 1
Required: \{\}
| +| `segmentationType` _string_ | segmentationType is the segmentation type for the subport (e.g. vlan). | | Enum: [inherit vlan]
MaxLength: 32
MinLength: 1
Required: \{\}
| -#### SubnetFilter +#### TrunkSubportStatus -SubnetFilter specifies a filter to select a subnet. At least one parameter must be specified. +TrunkSubportStatus represents an attached subport on a trunk. +It maps to gophercloud's trunks.Subport. + -_Validation:_ -- MinProperties: 1 _Appears in:_ -- [SubnetImport](#subnetimport) +- [TrunkResourceStatus](#trunkresourcestatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `ipVersion` _[IPVersion](#ipversion)_ | ipVersion of the existing resource | | Enum: [4 6]
| -| `gatewayIP` _[IPvAny](#ipvany)_ | gatewayIP is the IP address of the gateway of the existing resource | | MaxLength: 45
MinLength: 1
| -| `cidr` _[CIDR](#cidr)_ | cidr of the existing resource | | Format: cidr
MaxLength: 49
MinLength: 1
| -| `ipv6` _[IPv6Options](#ipv6options)_ | ipv6 options of the existing resource | | MinProperties: 1
| -| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this subnet is associated with. | | MaxLength: 253
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| +| `portID` _string_ | portID is the OpenStack ID of the Port attached as a subport. | | MaxLength: 1024
Optional: \{\}
| +| `segmentationID` _integer_ | segmentationID is the segmentation ID for the subport (e.g. VLAN ID). | | Optional: \{\}
| +| `segmentationType` _string_ | segmentationType is the segmentation type for the subport (e.g. vlan). | | MaxLength: 1024
Optional: \{\}
| -#### SubnetGateway +#### User +User is the Schema for an ORC resource. + + -_Appears in:_ -- [SubnetResourceSpec](#subnetresourcespec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `type` _[SubnetGatewayType](#subnetgatewaytype)_ | type specifies how the default gateway will be created. `Automatic`
specifies that neutron will automatically add a default gateway. This is
also the default if no Gateway is specified. `None` specifies that the
subnet will not have a default gateway. `IP` specifies that the subnet
will use a specific address as the default gateway, which must be
specified in `IP`. | | Enum: [None Automatic IP]
| -| `ip` _[IPvAny](#ipvany)_ | ip is the IP address of the default gateway, which must be specified if
Type is `IP`. It must be a valid IP address, either IPv4 or IPv6,
matching the IPVersion in SubnetResourceSpec. | | MaxLength: 45
MinLength: 1
| +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `User` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[UserSpec](#userspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[UserStatus](#userstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| -#### SubnetGatewayType +#### UserDataSpec -_Underlying type:_ _string_ +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 _Appears in:_ -- [SubnetGateway](#subnetgateway) +- [ServerResourceSpec](#serverresourcespec) +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `secretRef` _[KubernetesNameRef](#kubernetesnameref)_ | secretRef is a reference to a Secret containing the user data for this server. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| -#### SubnetImport +#### UserFilter -SubnetImport specifies an existing resource which will be imported instead of -creating a new one +UserFilter defines an existing resource by its properties _Validation:_ -- MaxProperties: 1 - MinProperties: 1 _Appears in:_ -- [SubnetSpec](#subnetspec) +- [UserImport](#userimport) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[SubnetFilter](#subnetfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| - - -#### SubnetResourceSpec +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +#### UserImport +UserImport specifies an existing resource which will be imported instead of +creating a new one +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 _Appears in:_ -- [SubnetSpec](#subnetspec) +- [UserSpec](#userspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name is a human-readable name of the subnet. If not set, the object's name will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _[NeutronDescription](#neutrondescription)_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `networkRef` _[KubernetesNameRef](#kubernetesnameref)_ | networkRef is a reference to the ORC Network which this subnet is associated with. | | MaxLength: 253
MinLength: 1
| -| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags which will be applied to the subnet. | | MaxItems: 64
MaxLength: 255
MinLength: 1
| -| `ipVersion` _[IPVersion](#ipversion)_ | ipVersion is the IP version for the subnet. | | Enum: [4 6]
| -| `cidr` _[CIDR](#cidr)_ | cidr is the address CIDR of the subnet. It must match the IP version specified in IPVersion. | | Format: cidr
MaxLength: 49
MinLength: 1
| -| `allocationPools` _[AllocationPool](#allocationpool) array_ | allocationPools are IP Address pools that will be available for DHCP. IP
addresses must be in CIDR. | | MaxItems: 32
| -| `gateway` _[SubnetGateway](#subnetgateway)_ | gateway specifies the default gateway of the subnet. If not specified,
neutron will add one automatically. To disable this behaviour, specify a
gateway with a type of None. | | | -| `enableDHCP` _boolean_ | enableDHCP will either enable to disable the DHCP service. | | | -| `dnsNameservers` _[IPvAny](#ipvany) array_ | dnsNameservers are the nameservers to be set via DHCP. | | MaxItems: 16
MaxLength: 45
MinLength: 1
| -| `dnsPublishFixedIP` _boolean_ | dnsPublishFixedIP will either enable or disable the publication of
fixed IPs to the DNS. Defaults to false. | | | -| `hostRoutes` _[HostRoute](#hostroute) array_ | hostRoutes are any static host routes to be set via DHCP. | | MaxItems: 256
| -| `ipv6` _[IPv6Options](#ipv6options)_ | ipv6 contains IPv6-specific options. It may only be set if IPVersion is 6. | | MinProperties: 1
| -| `routerRef` _[KubernetesNameRef](#kubernetesnameref)_ | routerRef specifies a router to attach the subnet to | | MaxLength: 253
MinLength: 1
| -| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project this resource is associated with.
Typically, only used by admin. | | MaxLength: 253
MinLength: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[UserFilter](#userfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| -#### SubnetResourceStatus - +#### UserResourceSpec +UserResourceSpec contains the desired state of the resource. _Appears in:_ -- [SubnetStatus](#subnetstatus) +- [UserSpec](#userspec) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is the human-readable name of the subnet. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `ipVersion` _integer_ | ipVersion specifies IP version, either `4' or `6'. | | | -| `cidr` _string_ | cidr representing IP range for this subnet, based on IP version. | | MaxLength: 1024
| -| `gatewayIP` _string_ | gatewayIP is the default gateway used by devices in this subnet, if any. | | MaxLength: 1024
| -| `dnsNameservers` _string array_ | dnsNameservers is a list of name servers used by hosts in this subnet. | | MaxItems: 16
items:MaxLength: 1024
| -| `dnsPublishFixedIP` _boolean_ | dnsPublishFixedIP specifies whether the fixed IP addresses are published to the DNS. | | | -| `allocationPools` _[AllocationPoolStatus](#allocationpoolstatus) array_ | allocationPools is a list of sub-ranges within CIDR available for dynamic
allocation to ports. | | MaxItems: 32
| -| `hostRoutes` _[HostRouteStatus](#hostroutestatus) array_ | hostRoutes is a list of routes that should be used by devices with IPs
from this subnet (not including local subnet route). | | MaxItems: 256
| -| `enableDHCP` _boolean_ | enableDHCP specifies whether DHCP is enabled for this subnet or not. | | | -| `networkID` _string_ | networkID is the ID of the network to which the subnet belongs. | | MaxLength: 1024
| -| `projectID` _string_ | projectID is the project owner of the subnet. | | MaxLength: 1024
| -| `ipv6AddressMode` _string_ | ipv6AddressMode specifies mechanisms for assigning IPv6 IP addresses. | | MaxLength: 1024
| -| `ipv6RAMode` _string_ | ipv6RAMode is the IPv6 router advertisement mode. It specifies
whether the networking service should transmit ICMPv6 packets. | | MaxLength: 1024
| -| `subnetPoolID` _string_ | subnetPoolID is the id of the subnet pool associated with the subnet. | | MaxLength: 1024
| -| `tags` _string array_ | tags optionally set via extensions/attributestags | | MaxItems: 64
items:MaxLength: 1024
| -| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | | -| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | | -| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `defaultProjectRef` _[KubernetesNameRef](#kubernetesnameref)_ | defaultProjectRef is a reference to the Default Project which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `enabled` _boolean_ | enabled defines whether a user is enabled or disabled | | Optional: \{\}
| +| `passwordRef` _[KubernetesNameRef](#kubernetesnameref)_ | passwordRef is a reference to a Secret containing the password
for this user. The Secret must contain a key named "password".
If not specified, the user is created without a password. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| -#### SubnetSpec +#### UserResourceStatus -SubnetSpec defines the desired state of an ORC object. +UserResourceStatus represents the observed state of the resource. _Appears in:_ -- [Subnet](#subnet) +- [UserStatus](#userstatus) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[SubnetImport](#subnetimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[SubnetResourceSpec](#subnetresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `domainID` _string_ | domainID is the ID of the Domain to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| +| `defaultProjectID` _string_ | defaultProjectID is the ID of the Default Project to which the user is associated with. | | MaxLength: 1024
Optional: \{\}
| +| `enabled` _boolean_ | enabled defines whether a user is enabled or disabled | | Optional: \{\}
| +| `passwordExpiresAt` _string_ | passwordExpiresAt is the timestamp at which the user's password expires. | | MaxLength: 1024
Optional: \{\}
| +| `appliedPasswordRef` _string_ | appliedPasswordRef is the name of the Secret containing the
password that was last applied to the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| -#### SubnetStatus +#### UserSpec -SubnetStatus defines the observed state of an ORC resource. +UserSpec defines the desired state of an ORC object. _Appears in:_ -- [Subnet](#subnet) +- [User](#user) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[SubnetResourceStatus](#subnetresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | - +| `import` _[UserImport](#userimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[UserResourceSpec](#userresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| - -#### UserDataSpec +#### UserStatus +UserStatus defines the observed state of an ORC resource. -_Validation:_ -- MaxProperties: 1 -- MinProperties: 1 _Appears in:_ -- [ServerResourceSpec](#serverresourcespec) +- [User](#user) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `secretRef` _[KubernetesNameRef](#kubernetesnameref)_ | secretRef is a reference to a Secret containing the user data for this server. | | MaxLength: 253
MinLength: 1
| +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[UserResourceStatus](#userresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### Volume @@ -3813,9 +5193,9 @@ Volume is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `Volume` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[VolumeSpec](#volumespec)_ | spec specifies the desired state of the resource. | | | -| `status` _[VolumeStatus](#volumestatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[VolumeSpec](#volumespec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[VolumeStatus](#volumestatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### VolumeAttachmentStatus @@ -3831,10 +5211,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `attachmentID` _string_ | attachmentID represents the attachment UUID. | | MaxLength: 1024
| -| `serverID` _string_ | serverID is the UUID of the server to which the volume is attached. | | MaxLength: 1024
| -| `device` _string_ | device is the name of the device in the instance. | | MaxLength: 1024
| -| `attachedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | attachedAt shows the date and time when the resource was attached. The date and time stamp format is ISO 8601. | | | +| `attachmentID` _string_ | attachmentID represents the attachment UUID. | | MaxLength: 1024
Optional: \{\}
| +| `serverID` _string_ | serverID is the UUID of the server to which the volume is attached. | | MaxLength: 1024
Optional: \{\}
| +| `device` _string_ | device is the name of the device in the instance. | | MaxLength: 1024
Optional: \{\}
| +| `attachedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | attachedAt shows the date and time when the resource was attached. The date and time stamp format is ISO 8601. | | Optional: \{\}
| #### VolumeFilter @@ -3851,10 +5231,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _string_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `size` _integer_ | size is the size of the volume in GiB. | | Minimum: 1
| -| `availabilityZone` _string_ | availabilityZone is the availability zone of the existing resource | | MaxLength: 255
| +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `size` _integer_ | size is the size of the volume in GiB. | | Minimum: 1
Optional: \{\}
| +| `availabilityZone` _string_ | availabilityZone is the availability zone of the existing resource | | MaxLength: 255
Optional: \{\}
| #### VolumeImport @@ -3873,8 +5253,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[VolumeFilter](#volumefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[VolumeFilter](#volumefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### VolumeMetadata @@ -3890,8 +5270,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is the name of the metadata | | MaxLength: 255
| -| `value` _string_ | value is the value of the metadata | | MaxLength: 255
| +| `name` _string_ | name is the name of the metadata | | MaxLength: 255
Required: \{\}
| +| `value` _string_ | value is the value of the metadata | | MaxLength: 255
Required: \{\}
| #### VolumeMetadataStatus @@ -3907,8 +5287,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is the name of the metadata | | MaxLength: 255
| -| `value` _string_ | value is the value of the metadata | | MaxLength: 255
| +| `name` _string_ | name is the name of the metadata | | MaxLength: 255
Optional: \{\}
| +| `value` _string_ | value is the value of the metadata | | MaxLength: 255
Optional: \{\}
| #### VolumeResourceSpec @@ -3924,12 +5304,13 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `size` _integer_ | size is the size of the volume, in gibibytes (GiB). | | Minimum: 1
| -| `volumeTypeRef` _[KubernetesNameRef](#kubernetesnameref)_ | volumeTypeRef is a reference to the ORC VolumeType which this resource is associated with. | | MaxLength: 253
MinLength: 1
| -| `availabilityZone` _string_ | availabilityZone is the availability zone in which to create the volume. | | MaxLength: 255
| -| `metadata` _[VolumeMetadata](#volumemetadata) array_ | Refer to Kubernetes API documentation for fields of `metadata`. | | MaxItems: 64
| +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `size` _integer_ | size is the size of the volume, in gibibytes (GiB). | | Minimum: 1
Required: \{\}
| +| `volumeTypeRef` _[KubernetesNameRef](#kubernetesnameref)_ | volumeTypeRef is a reference to the ORC VolumeType which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `availabilityZone` _string_ | availabilityZone is the availability zone in which to create the volume. | | MaxLength: 255
Optional: \{\}
| +| `metadata` _[VolumeMetadata](#volumemetadata) array_ | Refer to Kubernetes API documentation for fields of `metadata`. | | MaxItems: 64
Optional: \{\}
| +| `imageRef` _[KubernetesNameRef](#kubernetesnameref)_ | imageRef is a reference to an ORC Image. If specified, creates a
bootable volume from this image. The volume size must be >= the
image's min_disk requirement. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| #### VolumeResourceStatus @@ -3945,27 +5326,28 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `size` _integer_ | size is the size of the volume in GiB. | | | -| `status` _string_ | status represents the current status of the volume. | | MaxLength: 1024
| -| `availabilityZone` _string_ | availabilityZone is which availability zone the volume is in. | | MaxLength: 1024
| -| `attachments` _[VolumeAttachmentStatus](#volumeattachmentstatus) array_ | attachments is a list of attachments for the volume. | | MaxItems: 32
| -| `volumeType` _string_ | volumeType is the name of associated the volume type. | | MaxLength: 1024
| -| `snapshotID` _string_ | snapshotID is the ID of the snapshot from which the volume was created | | MaxLength: 1024
| -| `sourceVolID` _string_ | sourceVolID is the ID of another block storage volume from which the current volume was created | | MaxLength: 1024
| -| `backupID` _string_ | backupID is the ID of the backup from which the volume was restored | | MaxLength: 1024
| -| `metadata` _[VolumeMetadataStatus](#volumemetadatastatus) array_ | Refer to Kubernetes API documentation for fields of `metadata`. | | MaxItems: 64
| -| `userID` _string_ | userID is the ID of the user who created the volume. | | MaxLength: 1024
| -| `bootable` _boolean_ | bootable indicates whether this is a bootable volume. | | | -| `encrypted` _boolean_ | encrypted denotes if the volume is encrypted. | | | -| `replicationStatus` _string_ | replicationStatus is the status of replication. | | MaxLength: 1024
| -| `consistencyGroupID` _string_ | consistencyGroupID is the consistency group ID. | | MaxLength: 1024
| -| `multiattach` _boolean_ | multiattach denotes if the volume is multi-attach capable. | | | -| `host` _string_ | host is the identifier of the host holding the volume. | | MaxLength: 1024
| -| `tenantID` _string_ | tenantID is the ID of the project that owns the volume. | | MaxLength: 1024
| -| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | | -| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `size` _integer_ | size is the size of the volume in GiB. | | Optional: \{\}
| +| `status` _string_ | status represents the current status of the volume. | | MaxLength: 1024
Optional: \{\}
| +| `availabilityZone` _string_ | availabilityZone is which availability zone the volume is in. | | MaxLength: 1024
Optional: \{\}
| +| `attachments` _[VolumeAttachmentStatus](#volumeattachmentstatus) array_ | attachments is a list of attachments for the volume. | | MaxItems: 32
Optional: \{\}
| +| `volumeType` _string_ | volumeType is the name of associated the volume type. | | MaxLength: 1024
Optional: \{\}
| +| `snapshotID` _string_ | snapshotID is the ID of the snapshot from which the volume was created | | MaxLength: 1024
Optional: \{\}
| +| `sourceVolID` _string_ | sourceVolID is the ID of another block storage volume from which the current volume was created | | MaxLength: 1024
Optional: \{\}
| +| `backupID` _string_ | backupID is the ID of the backup from which the volume was restored | | MaxLength: 1024
Optional: \{\}
| +| `metadata` _[VolumeMetadataStatus](#volumemetadatastatus) array_ | Refer to Kubernetes API documentation for fields of `metadata`. | | MaxItems: 64
Optional: \{\}
| +| `userID` _string_ | userID is the ID of the user who created the volume. | | MaxLength: 1024
Optional: \{\}
| +| `bootable` _boolean_ | bootable indicates whether this is a bootable volume. | | Optional: \{\}
| +| `imageID` _string_ | imageID is the ID of the image this volume was created from, if any. | | MaxLength: 1024
Optional: \{\}
| +| `encrypted` _boolean_ | encrypted denotes if the volume is encrypted. | | Optional: \{\}
| +| `replicationStatus` _string_ | replicationStatus is the status of replication. | | MaxLength: 1024
Optional: \{\}
| +| `consistencyGroupID` _string_ | consistencyGroupID is the consistency group ID. | | MaxLength: 1024
Optional: \{\}
| +| `multiattach` _boolean_ | multiattach denotes if the volume is multi-attach capable. | | Optional: \{\}
| +| `host` _string_ | host is the identifier of the host holding the volume. | | MaxLength: 1024
Optional: \{\}
| +| `tenantID` _string_ | tenantID is the ID of the project that owns the volume. | | MaxLength: 1024
Optional: \{\}
| +| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
| +| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
| #### VolumeSpec @@ -3981,11 +5363,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[VolumeImport](#volumeimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[VolumeResourceSpec](#volumeresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[VolumeImport](#volumeimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[VolumeResourceSpec](#volumeresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### VolumeStatus @@ -4001,9 +5384,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[VolumeResourceStatus](#volumeresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[VolumeResourceStatus](#volumeresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| #### VolumeType @@ -4020,9 +5404,9 @@ VolumeType is the Schema for an ORC resource. | --- | --- | --- | --- | | `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | | `kind` _string_ | `VolumeType` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[VolumeTypeSpec](#volumetypespec)_ | spec specifies the desired state of the resource. | | | -| `status` _[VolumeTypeStatus](#volumetypestatus)_ | status defines the observed state of the resource. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[VolumeTypeSpec](#volumetypespec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[VolumeTypeStatus](#volumetypestatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| #### VolumeTypeExtraSpec @@ -4038,8 +5422,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is the name of the extraspec | | MaxLength: 255
| -| `value` _string_ | value is the value of the extraspec | | MaxLength: 255
| +| `name` _string_ | name is the name of the extraspec | | MaxLength: 255
Required: \{\}
| +| `value` _string_ | value is the value of the extraspec | | MaxLength: 255
Required: \{\}
| #### VolumeTypeExtraSpecStatus @@ -4055,8 +5439,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is the name of the extraspec | | MaxLength: 255
| -| `value` _string_ | value is the value of the extraspec | | MaxLength: 255
| +| `name` _string_ | name is the name of the extraspec | | MaxLength: 255
Optional: \{\}
| +| `value` _string_ | value is the value of the extraspec | | MaxLength: 255
Optional: \{\}
| #### VolumeTypeFilter @@ -4073,9 +5457,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _string_ | description of the existing resource | | MaxLength: 255
MinLength: 1
| -| `isPublic` _boolean_ | isPublic indicates whether the VolumeType is public. | | | +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `isPublic` _boolean_ | isPublic indicates whether the VolumeType is public. | | Optional: \{\}
| #### VolumeTypeImport @@ -4094,8 +5478,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
| -| `filter` _[VolumeTypeFilter](#volumetypefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
| +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[VolumeTypeFilter](#volumetypefilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| #### VolumeTypeResourceSpec @@ -4111,10 +5495,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
| -| `extraSpecs` _[VolumeTypeExtraSpec](#volumetypeextraspec) array_ | extraSpecs is a map of key-value pairs that define extra specifications for the volume type. | | MaxItems: 64
| -| `isPublic` _boolean_ | isPublic indicates whether the volume type is public. | | | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `extraSpecs` _[VolumeTypeExtraSpec](#volumetypeextraspec) array_ | extraSpecs is a map of key-value pairs that define extra specifications for the volume type. | | MaxItems: 64
Optional: \{\}
| +| `isPublic` _boolean_ | isPublic indicates whether the volume type is public. | | Optional: \{\}
| #### VolumeTypeResourceStatus @@ -4130,10 +5514,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
| -| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
| -| `extraSpecs` _[VolumeTypeExtraSpecStatus](#volumetypeextraspecstatus) array_ | extraSpecs is a map of key-value pairs that define extra specifications for the volume type. | | MaxItems: 64
| -| `isPublic` _boolean_ | isPublic indicates whether the VolumeType is public. | | | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `extraSpecs` _[VolumeTypeExtraSpecStatus](#volumetypeextraspecstatus) array_ | extraSpecs is a map of key-value pairs that define extra specifications for the volume type. | | MaxItems: 64
Optional: \{\}
| +| `isPublic` _boolean_ | isPublic indicates whether the VolumeType is public. | | Optional: \{\}
| #### VolumeTypeSpec @@ -4149,11 +5533,12 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `import` _[VolumeTypeImport](#volumetypeimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
| -| `resource` _[VolumeTypeResourceSpec](#volumetyperesourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | | -| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
| -| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | | -| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | | +| `import` _[VolumeTypeImport](#volumetypeimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[VolumeTypeResourceSpec](#volumetyperesourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| #### VolumeTypeStatus @@ -4169,8 +5554,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
| -| `id` _string_ | id is the unique identifier of the OpenStack resource. | | | -| `resource` _[VolumeTypeResourceStatus](#volumetyperesourcestatus)_ | resource contains the observed state of the OpenStack resource. | | | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[VolumeTypeResourceStatus](#volumetyperesourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| diff --git a/website/docs/development/api-design.md b/website/docs/development/api-design.md index 2fdd30b2b..79597cb84 100644 --- a/website/docs/development/api-design.md +++ b/website/docs/development/api-design.md @@ -32,7 +32,7 @@ This is located at `spec.resource` in the base object. It is only defined for [m * Where relevant, the `ResourceSpec` should include a `name` field to allow object name to be overridden. * All fields should use pre-defined validated types where possible, e.g. `OpenStackName`, `NeutronDescription`, `IPvAny`. -* Lists should have type `set` or `map` where possible, but `atomic` lists may be necessary where a struct has no merge key. +* Lists of structs should use `listType=map` with an appropriate `listMapKey` where possible. `listType=set` should only be used for lists of primitives (e.g., strings). `listType=atomic` may be necessary where a struct has no suitable merge key. ### ResourceStatus @@ -83,3 +83,4 @@ You should update `examples/components/kustomizeconfig/kustomizeconfig.yaml` wit * Do not use unsigned integers: use `intN` with a kubebuilder marker validating for a minimum of 0. * Optional fields should have the `omitempty` tag. * Optional fields should be pointers, unless their zero-value is also the OpenStack default, or we can be very confident that we will never need to distinguish between empty and unset values. e.g. Will we ever want to set a value explicitly to the empty string? +* ResourceSpec and Filter fields must reference other ORC objects using `*KubernetesNameRef` with a `Ref` suffix (e.g., `ProjectRef`), not OpenStack resources directly by UUID (e.g., `ProjectID *string`). Exceptions include bare `ID` fields (used for `spec.import.id`) and non-resource IDs like `SegmentationID`. diff --git a/website/docs/development/godoc/generic-interfaces.md b/website/docs/development/godoc/generic-interfaces.md index 2d0021572..817983747 100644 --- a/website/docs/development/godoc/generic-interfaces.md +++ b/website/docs/development/godoc/generic-interfaces.md @@ -15,6 +15,8 @@ import "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/g - [type DeleteResourceActuator](<#DeleteResourceActuator>) - [type ORCApplyConfig](<#ORCApplyConfig>) - [type ORCStatusApplyConfig](<#ORCStatusApplyConfig>) +- [type ORCStatusApplyConfigWithID](<#ORCStatusApplyConfigWithID>) +- [type ORCStatusApplyConfigWithLastSyncTime](<#ORCStatusApplyConfigWithLastSyncTime>) - [type ReconcileResourceActuator](<#ReconcileResourceActuator>) - [type ResourceController](<#ResourceController>) - [type ResourceHelperFactory](<#ResourceHelperFactory>) @@ -23,7 +25,7 @@ import "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/g -## type [APIObjectAdapter]() +## type [APIObjectAdapter]() @@ -39,6 +41,8 @@ type APIObjectAdapter[orcObjectPT any, resourceSpecT any, filterT any] interface GetManagementPolicy() orcv1alpha1.ManagementPolicy GetManagedOptions() *orcv1alpha1.ManagedOptions + GetResyncPeriod() *metav1.Duration + GetLastSyncTime() *metav1.Time GetStatusID() *string GetResourceSpec() *resourceSpecT @@ -90,7 +94,7 @@ type BaseResourceActuator[ ``` -## type [Controller]() +## type [Controller]() @@ -98,6 +102,7 @@ type BaseResourceActuator[ type Controller interface { SetupWithManager(context.Context, ctrl.Manager, controller.Options) error GetName() string + SetDefaultResyncPeriod(time.Duration) } ``` @@ -203,14 +208,37 @@ type ORCApplyConfig[objectApplyPT any, statusApplyPT ORCStatusApplyConfig[status ``` -## type [ORCStatusApplyConfig]() +## type [ORCStatusApplyConfig]() -ORCStatusApplyConfig is an interface implemented by the status of any apply configuration for an ORC API object. It has Conditions and an ID field. +ORCStatusApplyConfig is an interface implemented by the status of any apply configuration for an ORC API object. ```go type ORCStatusApplyConfig[statusApplyPT any] interface { WithConditions(...*applyconfigv1.ConditionApplyConfiguration) statusApplyPT +} +``` + + +## type [ORCStatusApplyConfigWithID]() + +ORCStatusApplyConfigWithID extends ORCStatusApplyConfigWithLastSyncTime with an ID field. This is required by resources that have an OpenStack\-assigned ID stored in status.id. Resources without an ID \(e.g. relationship resources like RoleAssignment\) use only ORCStatusApplyConfig. + +```go +type ORCStatusApplyConfigWithID[statusApplyPT any] interface { WithID(id string) statusApplyPT + // contains filtered or unexported methods +} +``` + + +## type [ORCStatusApplyConfigWithLastSyncTime]() + +ORCStatusApplyConfigWithLastSyncTime extends ORCStatusApplyConfig with a LastSyncTime field. + +```go +type ORCStatusApplyConfigWithLastSyncTime[statusApplyPT any] interface { + WithLastSyncTime(metav1.Time) statusApplyPT + // contains filtered or unexported methods } ``` @@ -245,7 +273,7 @@ type ReconcileResourceActuator[orcObjectPT, osResourceT any] interface { ``` -## type [ResourceController]() +## type [ResourceController]() @@ -313,7 +341,7 @@ type ResourceReconciler[orcObjectPT, osResourceT any] func(ctx context.Context, ``` -## type [ResourceStatusWriter]() +## type [ResourceStatusWriter]() ResourceStatusWriter defines methods for writing an ORC object status diff --git a/website/docs/development/godoc/reconcile-status.md b/website/docs/development/godoc/reconcile-status.md index 92bf7c3c3..1205cd504 100644 --- a/website/docs/development/godoc/reconcile-status.md +++ b/website/docs/development/godoc/reconcile-status.md @@ -9,15 +9,18 @@ import "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/g ## Index - [type ReconcileStatus](<#ReconcileStatus>) + - [func ExternallyDeleted\(\) ReconcileStatus](<#ExternallyDeleted>) - [func NeedsRefresh\(\) ReconcileStatus](<#NeedsRefresh>) - [func NewReconcileStatus\(\) ReconcileStatus](<#NewReconcileStatus>) - [func WaitingOnFinalizer\(finalizer string\) ReconcileStatus](<#WaitingOnFinalizer>) - [func WaitingOnObject\(kind, name string, waitingOn WaitingOnEvent\) ReconcileStatus](<#WaitingOnObject>) - [func WaitingOnOpenStack\(waitingOn WaitingOnEvent, pollingPeriod time.Duration\) ReconcileStatus](<#WaitingOnOpenStack>) - [func WrapError\(err error\) ReconcileStatus](<#WrapError>) + - [func \(r ReconcileStatus\) ExternallyDeleted\(\) ReconcileStatus](<#ReconcileStatus.ExternallyDeleted>) - [func \(r ReconcileStatus\) GetError\(\) error](<#ReconcileStatus.GetError>) - [func \(r ReconcileStatus\) GetProgressMessages\(\) \[\]string](<#ReconcileStatus.GetProgressMessages>) - [func \(r ReconcileStatus\) GetRequeue\(\) time.Duration](<#ReconcileStatus.GetRequeue>) + - [func \(r ReconcileStatus\) IsExternallyDeleted\(\) bool](<#ReconcileStatus.IsExternallyDeleted>) - [func \(r ReconcileStatus\) NeedsRefresh\(\) ReconcileStatus](<#ReconcileStatus.NeedsRefresh>) - [func \(r ReconcileStatus\) NeedsReschedule\(\) \(bool, error\)](<#ReconcileStatus.NeedsReschedule>) - [func \(r ReconcileStatus\) Return\(log logr.Logger\) \(ctrl.Result, error\)](<#ReconcileStatus.Return>) @@ -44,8 +47,17 @@ You MUST use the return value of any method which returns ReconcileStatus: the r type ReconcileStatus = *reconcileStatus ``` + +### func [ExternallyDeleted]() + +```go +func ExternallyDeleted() ReconcileStatus +``` + +ExternallyDeleted is a convenience method which returns a new ReconcileStatus with ExternallyDeleted. + -### func [NeedsRefresh]() +### func [NeedsRefresh]() ```go func NeedsRefresh() ReconcileStatus @@ -54,7 +66,7 @@ func NeedsRefresh() ReconcileStatus NeedsRefresh is a convenience method which returns a new ReconcileStatus with NeedsRefresh. -### func [NewReconcileStatus]() +### func [NewReconcileStatus]() ```go func NewReconcileStatus() ReconcileStatus @@ -63,7 +75,7 @@ func NewReconcileStatus() ReconcileStatus NewReconcileStatus returns an empty ReconcileStatus -### func [WaitingOnFinalizer]() +### func [WaitingOnFinalizer]() ```go func WaitingOnFinalizer(finalizer string) ReconcileStatus @@ -72,7 +84,7 @@ func WaitingOnFinalizer(finalizer string) ReconcileStatus WaitingOnFinalizer is a convenience method which returns a new ReconcileStatus with WaitingOnFinalizer. -### func [WaitingOnObject]() +### func [WaitingOnObject]() ```go func WaitingOnObject(kind, name string, waitingOn WaitingOnEvent) ReconcileStatus @@ -81,7 +93,7 @@ func WaitingOnObject(kind, name string, waitingOn WaitingOnEvent) ReconcileStatu WaitingOnObject is a convenience method which returns a new ReconcileStatus with WaitingOnObject. -### func [WaitingOnOpenStack]() +### func [WaitingOnOpenStack]() ```go func WaitingOnOpenStack(waitingOn WaitingOnEvent, pollingPeriod time.Duration) ReconcileStatus @@ -90,7 +102,7 @@ func WaitingOnOpenStack(waitingOn WaitingOnEvent, pollingPeriod time.Duration) R WaitingOnOpenStack is a convenience method which returns a new ReconcileStatus with WaitingOnOpenStack. -### func [WrapError]() +### func [WrapError]() ```go func WrapError(err error) ReconcileStatus @@ -98,8 +110,17 @@ func WrapError(err error) ReconcileStatus WrapError returns a ReconcileStatus containing the given error + +### func \(ReconcileStatus\) [ExternallyDeleted]() + +```go +func (r ReconcileStatus) ExternallyDeleted() ReconcileStatus +``` + +ExternallyDeleted returns a ReconcileStatus indicating that the OpenStack resource referenced by status.id has been deleted outside of ORC. The caller is expected to clear status.id and add an appropriate progress message. + -### func \(ReconcileStatus\) [GetError]() +### func \(ReconcileStatus\) [GetError]() ```go func (r ReconcileStatus) GetError() error @@ -108,7 +129,7 @@ func (r ReconcileStatus) GetError() error GetError returns an error representing all errors which have been added to this ReconcileStatus. If multiple errors have been added they will have been combined with errors.Join\(\) -### func \(ReconcileStatus\) [GetProgressMessages]() +### func \(ReconcileStatus\) [GetProgressMessages]() ```go func (r ReconcileStatus) GetProgressMessages() []string @@ -117,7 +138,7 @@ func (r ReconcileStatus) GetProgressMessages() []string GetProgressMessages returns all progress messages which have been added to this ReconcileStatus -### func \(ReconcileStatus\) [GetRequeue]() +### func \(ReconcileStatus\) [GetRequeue]() ```go func (r ReconcileStatus) GetRequeue() time.Duration @@ -125,8 +146,17 @@ func (r ReconcileStatus) GetRequeue() time.Duration GetRequeue returns the time after which the current object should be reconciled again. A value of 0 indicates that no requeue is requested. + +### func \(ReconcileStatus\) [IsExternallyDeleted]() + +```go +func (r ReconcileStatus) IsExternallyDeleted() bool +``` + +IsExternallyDeleted returns true if the ReconcileStatus indicates that the OpenStack resource was deleted externally. + -### func \(ReconcileStatus\) [NeedsRefresh]() +### func \(ReconcileStatus\) [NeedsRefresh]() ```go func (r ReconcileStatus) NeedsRefresh() ReconcileStatus @@ -135,7 +165,7 @@ func (r ReconcileStatus) NeedsRefresh() ReconcileStatus NeedsRefresh indicates that the resource status needs to be refreshed. It sets an appropriate progress message and ensures that the object will be reconciled again immediately. -### func \(ReconcileStatus\) [NeedsReschedule]() +### func \(ReconcileStatus\) [NeedsReschedule]() ```go func (r ReconcileStatus) NeedsReschedule() (bool, error) @@ -146,7 +176,7 @@ NeedsReschedule returns a boolean value indicating whether the ReconcileStatus w NeedsReschedule is used to shortcut reconciliation if any precondition has not been met. -### func \(ReconcileStatus\) [Return]() +### func \(ReconcileStatus\) [Return]() ```go func (r ReconcileStatus) Return(log logr.Logger) (ctrl.Result, error) @@ -157,7 +187,7 @@ Return returns the the \(ctrl.Result, error\) expected by controller\-runtime fo If a ReconcileStatus contains a TerminalError, Return will log the error directly instead of returning it to controller\-runtime, as this would cause an undesirable reschedule. -### func \(ReconcileStatus\) [WaitingOnFinalizer]() +### func \(ReconcileStatus\) [WaitingOnFinalizer]() ```go func (r ReconcileStatus) WaitingOnFinalizer(finalizer string) ReconcileStatus @@ -166,7 +196,7 @@ func (r ReconcileStatus) WaitingOnFinalizer(finalizer string) ReconcileStatus WaitingOnFinalizer adds a progress message indicating that we are waiting for a specific finalizer to be removed. -### func \(ReconcileStatus\) [WaitingOnObject]() +### func \(ReconcileStatus\) [WaitingOnObject]() ```go func (r ReconcileStatus) WaitingOnObject(kind, name string, waitingOn WaitingOnEvent) ReconcileStatus @@ -175,7 +205,7 @@ func (r ReconcileStatus) WaitingOnObject(kind, name string, waitingOn WaitingOnE WaitingOnObject adds a progress message indicating that we are waiting on a kubernetes object of type kind with name. We expect the controller to have an appropriate watch and handler for this event, so WaitingOnObject does not add an explicit requeue. -### func \(ReconcileStatus\) [WaitingOnOpenStack]() +### func \(ReconcileStatus\) [WaitingOnOpenStack]() ```go func (r ReconcileStatus) WaitingOnOpenStack(waitingOn WaitingOnEvent, pollingPeriod time.Duration) ReconcileStatus @@ -184,7 +214,7 @@ func (r ReconcileStatus) WaitingOnOpenStack(waitingOn WaitingOnEvent, pollingPer WaitingOnOpenStack indicates that we are waiting for an event on the current OpenStack resource. It adds an appropriate progress message. It also adds a requeue with the requested polling period, as we are not able to receive triggers for OpenStack events. -### func \(ReconcileStatus\) [WithError]() +### func \(ReconcileStatus\) [WithError]() ```go func (r ReconcileStatus) WithError(err error) ReconcileStatus @@ -193,7 +223,7 @@ func (r ReconcileStatus) WithError(err error) ReconcileStatus WithError returns a ReconcileStatus containing the given error joined to any existing errors. -### func \(ReconcileStatus\) [WithProgressMessage]() +### func \(ReconcileStatus\) [WithProgressMessage]() ```go func (r ReconcileStatus) WithProgressMessage(msgs ...string) ReconcileStatus @@ -202,7 +232,7 @@ func (r ReconcileStatus) WithProgressMessage(msgs ...string) ReconcileStatus WithProgressMessage returns a ReconcileStatus with the given progress messages in addition to any already present. -### func \(ReconcileStatus\) [WithReconcileStatus]() +### func \(ReconcileStatus\) [WithReconcileStatus]() ```go func (r ReconcileStatus) WithReconcileStatus(o ReconcileStatus) ReconcileStatus @@ -211,7 +241,7 @@ func (r ReconcileStatus) WithReconcileStatus(o ReconcileStatus) ReconcileStatus WithReconcileStatus returns a ReconcileStatus combining all properties of the given ReconcileStatus. -### func \(ReconcileStatus\) [WithRequeue]() +### func \(ReconcileStatus\) [WithRequeue]() ```go func (r ReconcileStatus) WithRequeue(requeue time.Duration) ReconcileStatus @@ -220,7 +250,7 @@ func (r ReconcileStatus) WithRequeue(requeue time.Duration) ReconcileStatus WithRequeue returns a ReconcileStatus with a request to requeue after the given time. If the ReconcileStatus already requests a requeue, the returned object will have the lesser of the existing and requested requeues. -## type [WaitingOnEvent]() +## type [WaitingOnEvent]() WaitingOnEvent represents the type of event we are waiting on diff --git a/website/docs/development/scaffolding.md b/website/docs/development/scaffolding.md index 7c7c33bf7..d1417f9d0 100644 --- a/website/docs/development/scaffolding.md +++ b/website/docs/development/scaffolding.md @@ -62,6 +62,7 @@ The scaffolding tool generates the following files: ### Tests +- `test/apivalidations/_test.go` - API validation tests (management policy, immutability) - `internal/controllers//tests/-create-minimal/` - Minimal creation test - `internal/controllers//tests/-create-full/` - Full creation test - `internal/controllers//tests/-import/` - Import test @@ -171,7 +172,7 @@ controllers := []interfaces.Controller{ Search the generated code for `TODO(scaffolding)` markers and implement each one: ```bash -grep -r "TODO(scaffolding)" api/ internal/controllers// +grep -r "TODO(scaffolding)" api/ internal/controllers// test/apivalidations/ ``` Key areas requiring implementation: @@ -179,7 +180,8 @@ Key areas requiring implementation: - [API types](api-design.md): Define `Filter`, `ResourceSpec`, and `ResourceStatus` structs - [Actuator](interfaces.md#actuator): Implement `CreateResource`, `DeleteResource`, and optionally `GetResourceReconcilers` - [Status writer](interfaces.md#resourcestatuswriter): Implement `ResourceAvailableStatus` and `ApplyResourceStatus` -- [Tests](writing-tests.md): Ensure the tests for your controller are complete +- [Tests](writing-tests.md): Ensure the tests for your controller are complete, including + [API validation tests](writing-tests.md#api-validation-tests) for any resource-specific validations !!! note diff --git a/website/docs/development/writing-tests.md b/website/docs/development/writing-tests.md index 0f8c0ccbd..e01b8bf8f 100644 --- a/website/docs/development/writing-tests.md +++ b/website/docs/development/writing-tests.md @@ -14,8 +14,11 @@ fields, you should add tests for those fields. All APIs are expected to have good API validation test coverage. API validation tests ensure that any validations defined in the -API and included in the CRD perform as expected. Add API validation tests for -your controller in `test/apivalidations`. +API and included in the CRD perform as expected. They run against a real +Kubernetes API server (via envtest) using Server-Side Apply, exercising the CEL +rules and OpenAPI schema validations baked into the CRDs. + +Add API validation tests for your controller in `test/apivalidations/`. ### Controller-specific tests @@ -36,7 +39,7 @@ can specify modules that you want to test by passing the package's path, separated by a blank space, for example: ```bash -TEST_PATHS="./internal/controller/server ./internal/controller/image" make test +TEST_PATHS="./internal/controllers/server ./internal/controllers/image" make test ``` ## E2E tests diff --git a/website/docs/index.md b/website/docs/index.md index 95edde167..aae4dc7cd 100644 --- a/website/docs/index.md +++ b/website/docs/index.md @@ -53,12 +53,14 @@ You define OpenStack resources as Kubernetes custom resources. ORC watches these ## Maturity -While we currently cover a limited subset of OpenStack resources, we focus on -making existing controllers as correct and predictable as possible. - ORC is deployed and used in production environments and is notably a dependency of Cluster API's [OpenStack provider][capo]. +The Kubernetes API is currently `v1alpha1`. The core API patterns are stable and +we do not anticipate major structural changes, but the API is still evolving as +we add new controllers and features. We do not have a timeline for graduation to +`v1beta1`. + ORC versioning follows [semver]: there will be no breaking changes within a major release. @@ -76,6 +78,10 @@ We welcome contributions of all kinds! Whether you're fixing bugs, adding new fe * Make your changes and test thoroughly. * Submit a pull request with a clear description of your changes. +For significant new features or architectural changes, please review our +[enhancement proposal process](https://github.com/k-orc/openstack-resource-controller/tree/main/enhancements) +before starting work. + If you're unsure where to start, check out the [open issues](https://github.com/k-orc/openstack-resource-controller/issues) and feel free to ask questions or propose ideas! diff --git a/website/docs/user-guide/drift-detection.md b/website/docs/user-guide/drift-detection.md new file mode 100644 index 000000000..c79d14680 --- /dev/null +++ b/website/docs/user-guide/drift-detection.md @@ -0,0 +1,146 @@ +# Drift Detection and External Deletion Handling + +ORC can periodically reconcile resources to detect and correct configuration drift — changes made to OpenStack resources outside of ORC's control. This feature also detects when managed resources have been deleted directly from OpenStack and recreates them automatically. + +## Enabling Drift Detection + +Drift detection is disabled by default. Enable it per-resource by setting `spec.resyncPeriod`: + +```yaml +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Network +metadata: + name: critical-network +spec: + cloudCredentialsRef: + secretName: openstack-clouds + cloudName: openstack + managementPolicy: managed + resyncPeriod: 1h # Re-check OpenStack every hour + resource: + description: Critical application network +``` + +The `resyncPeriod` field accepts any Go duration string: `10m`, `1h`, `24h`, etc. Very low values can create a high volume of OpenStack API calls. + +**Default:** `0` (disabled). When disabled, ORC only reconciles resources in response to spec changes or controller restarts. + +### Setting a Global Default + +To enable drift detection for all resources without setting `resyncPeriod` on each one, configure the manager's `--default-resync-period` flag: + +```yaml +spec: + containers: + - name: manager + args: + - --default-resync-period=10h +``` + +Per-resource `spec.resyncPeriod` takes precedence over this default when set. + +!!! note + + Conservative resync periods (e.g., `1h` or `10h`) are recommended in production to avoid excessive OpenStack API calls. + +## How It Works + +After a resource reaches a stable state (`Progressing=False`), ORC schedules a reconciliation after the configured `resyncPeriod`. On each resync: + +1. ORC fetches the current state of the OpenStack resource. +2. For **managed** resources: if drift is detected, ORC updates the resource to match the Kubernetes spec. +3. For **unmanaged** resources: ORC refreshes `status.resource` to reflect the current OpenStack state, but makes no changes. +4. The next resync is scheduled. + +A small random jitter ([0%, +20%]) is applied to `resyncPeriod` to spread reconciliations and avoid thundering-herd effects. + +!!! note + + Resources in a terminal error state (`Progressing=False` with reason `InvalidConfiguration` or `UnrecoverableError`) are **not** periodically resynced. Terminal errors require manual intervention to resolve. + +## Tracking Sync Status + +Every ORC resource has a `status.lastSyncTime` field that records when ORC last successfully reconciled with OpenStack: + +```bash +kubectl get network critical-network -o jsonpath='{.status.lastSyncTime}' +# 2026-02-03T10:30:00Z +``` + +ORC persists this timestamp in the Kubernetes status. After a controller restart, it uses `lastSyncTime` to determine when the next resync should occur, preventing a thundering herd of reconciliations on startup. + +## External Deletion Handling + +When a resource is deleted directly from OpenStack (bypassing ORC), the behavior depends on how ORC originally obtained the resource. + +### ORC-Created Resources (Managed, Not Imported) + +If you created the resource through ORC's `spec.resource` field, ORC **recreates** it automatically: + +1. ORC detects the resource is missing from OpenStack (the ID stored in `status.id` no longer exists). +2. ORC clears `status.id`. +3. On the next reconcile, ORC creates a new OpenStack resource. +4. The new resource ID is stored in `status.id`. + +The ORC object continues to exist and becomes `Available=True` again once the resource is recreated. + +```yaml +# This type of resource will be recreated if deleted from OpenStack +spec: + managementPolicy: managed + resyncPeriod: 10m # Enable resync to detect deletion quickly + resource: # Resource was created by ORC + description: My application network +``` + +!!! warning + + Recreation produces a new OpenStack resource with a **new ID**. Any OpenStack resources (outside ORC) that referenced the old ID will need to be updated manually. + +### Imported Resources (Terminal Error) + +If you imported an existing resource using `spec.import`, ORC reports a **terminal error** when the resource is deleted from OpenStack: + +- `Available=False` +- `Progressing=False` +- Condition reason: `UnrecoverableError` +- Message: `resource has been deleted from OpenStack` + +ORC does **not** recreate imported resources because it did not create them originally, and recreating a new empty resource would not restore what was lost. + +```yaml +# Unmanaged resources enter terminal error if deleted from OpenStack +spec: + managementPolicy: unmanaged + import: + filter: + name: public # Was imported by filter +``` + +To recover: delete and recreate the ORC object pointing at a newly created OpenStack resource. + +### Summary Table + +| Resource Type | How Obtained | External Deletion Behavior | +|--------------|--------------|---------------------------| +| Managed | `spec.resource` | **Recreated** automatically | +| Unmanaged | `spec.import.*` | **Terminal error** | + +## Implications for Dependent Resources + +OpenStack enforces referential integrity for most resource relationships (e.g., a Network cannot be deleted while Subnets exist). If an external deletion manages to bypass these constraints (e.g., direct database manipulation), the behavior of dependent ORC resources follows these rules: + +### If a Parent Resource Is Recreated + +When a parent resource (e.g., Network) is recreated by ORC, dependent resources that reference it (e.g., Subnets) detect the parent as available again but may encounter errors when OpenStack rejects operations referencing the old parent ID. **Manual intervention may be required** to recreate dependent resources against the new parent. + +### If a Parent Resource Enters Terminal Error + +When a parent resource enters terminal error: + +- **Dependent resources waiting on it** (e.g., a Subnet waiting for its Network): ORC will not proceed — it waits until the parent becomes available again. The dependent is not itself in an error state; it is just waiting. +- **Dependent resources already created**: ORC continues managing them normally. If ORC attempts to update a dependent resource that references a deleted parent in OpenStack, the behavior depends on what OpenStack returns for that operation. + +!!! warning + + If a parent resource is externally deleted in a way that bypasses OpenStack's referential integrity checks, the resulting state may require manual cleanup of both the parent and dependent resources. This is an unusual operational scenario and not specific to drift detection. diff --git a/website/docs/user-guide/index.md b/website/docs/user-guide/index.md index 4945fcdef..d30c84dd3 100644 --- a/website/docs/user-guide/index.md +++ b/website/docs/user-guide/index.md @@ -122,6 +122,15 @@ spec: ipVersion: 4 ``` +### Drift Detection and External Deletion + +ORC can periodically reconcile resources to detect configuration drift and recreate managed resources that are deleted directly from OpenStack. See [Drift Detection](drift-detection.md) for details on: + +- How to enable periodic resync with `spec.resyncPeriod` +- How ORC handles externally deleted resources (recreation vs. terminal error) +- How to verify that recreation occurred by checking `status.id` +- Implications for dependent resources + ### Understanding Status and Conditions Every ORC resource reports its status through two conditions: `Available` (whether the resource is ready for use) and `Progressing` (whether ORC is still working on it). For detailed information about conditions and their meanings, see [Troubleshooting: Status Conditions Explained](../troubleshooting.md#status-conditions-explained). diff --git a/website/mkdocs.yml b/website/mkdocs.yml index e71fbe9e9..01f6d8815 100644 --- a/website/mkdocs.yml +++ b/website/mkdocs.yml @@ -7,7 +7,9 @@ nav: - Getting Started: - Installation: installation.md - Quick Start: getting-started.md - - User Guide: user-guide/index.md + - User Guide: + - Overview: user-guide/index.md + - Drift Detection: user-guide/drift-detection.md - CRD Reference: crd-reference.md - Troubleshooting: troubleshooting.md - Contributing: