From 39145ac421eb7fa092324026186ef784d3c8232a Mon Sep 17 00:00:00 2001 From: yaroslavborbat Date: Wed, 30 Oct 2024 18:36:25 +0300 Subject: [PATCH] improve conds Signed-off-by: yaroslavborbat --- api/core/v1alpha2/cvicondition/condition.go | 2 + api/core/v1alpha2/vdcondition/condition.go | 4 ++ api/core/v1alpha2/vdscondition/condition.go | 2 + api/core/v1alpha2/vicondition/condition.go | 2 + api/core/v1alpha2/vmipcondition/condition.go | 4 ++ api/core/v1alpha2/vmiplcondition/condition.go | 2 + crds/clustervirtualimages.yaml | 70 +++++++++++++++---- crds/virtualdisks.yaml | 70 +++++++++++++++---- crds/virtualdisksnapshots.yaml | 70 +++++++++++++++---- crds/virtualimages.yaml | 70 +++++++++++++++---- crds/virtualmachineipaddresses.yaml | 70 +++++++++++++++---- crds/virtualmachineipaddressleases.yaml | 70 +++++++++++++++---- .../cvi/internal/datasource_ready.go | 1 + .../pkg/controller/cvi/internal/life_cycle.go | 1 + .../vd/internal/datasource_ready.go | 1 + .../pkg/controller/vd/internal/life_cycle.go | 1 + .../pkg/controller/vd/internal/resizing.go | 1 + .../controller/vd/internal/snapshotting.go | 1 + .../vdsnapshot/internal/life_cycle.go | 1 + .../vdsnapshot/internal/virtual_disk_ready.go | 1 + .../vi/internal/datasource_ready.go | 1 + .../pkg/controller/vi/internal/life_cycle.go | 1 + .../vmip/internal/iplease_handler.go | 15 ++-- .../vmip/internal/lifecycle_handler.go | 59 ++++++++-------- .../vmiplease/internal/lifecycle_handler.go | 21 +++--- 25 files changed, 407 insertions(+), 134 deletions(-) diff --git a/api/core/v1alpha2/cvicondition/condition.go b/api/core/v1alpha2/cvicondition/condition.go index 529db762d..95197777c 100644 --- a/api/core/v1alpha2/cvicondition/condition.go +++ b/api/core/v1alpha2/cvicondition/condition.go @@ -34,6 +34,7 @@ type ( ) const ( + DatasourceReadyReasonUnknown DatasourceReadyReason = "Unknown" // DatasourceReady indicates that the datasource is ready for use, allowing the import process to start. DatasourceReady DatasourceReadyReason = "DatasourceReady" // ContainerRegistrySecretNotFound indicates that the container registry secret was not found, which prevents the import process from starting. @@ -45,6 +46,7 @@ const ( // VirtualDiskNotReady indicates that the `VirtualDisk` datasource is not ready, which prevents the import process from starting. VirtualDiskNotReady DatasourceReadyReason = "VirtualDiskNotReady" + ReadyReasonUnknown ReadyReason = "Unknown" // WaitForUserUpload indicates that the `ClusterVirtualImage` is waiting for the user to upload a datasource for the import process to continue. WaitForUserUpload ReadyReason = "WaitForUserUpload" // Provisioning indicates that the provisioning process is currently in progress. diff --git a/api/core/v1alpha2/vdcondition/condition.go b/api/core/v1alpha2/vdcondition/condition.go index 622e2e1d7..63dabbf09 100644 --- a/api/core/v1alpha2/vdcondition/condition.go +++ b/api/core/v1alpha2/vdcondition/condition.go @@ -42,6 +42,7 @@ type ( ) const ( + DatasourceReadyReasonUnknown DatasourceReadyReason = "Unknown" // DatasourceReady indicates that the datasource is ready for use, allowing the import process to start. DatasourceReady DatasourceReadyReason = "DatasourceReady" // ContainerRegistrySecretNotFound indicates that the container registry secret was not found, which prevents the import process from starting. @@ -53,6 +54,7 @@ const ( // VirtualDiskSnapshotNotReady indicates that the `VirtualDiskSnapshot` datasource is not ready, which prevents the import process from starting. VirtualDiskSnapshotNotReady DatasourceReadyReason = "VirtualDiskSnapshot" + ReadyReasonUnknown ReadyReason = "Unknown" // WaitForUserUpload indicates that the `VirtualDisk` is waiting for the user to upload a datasource for the import process to continue. WaitForUserUpload ReadyReason = "WaitForUserUpload" // Provisioning indicates that the provisioning process is currently in progress. @@ -68,6 +70,7 @@ const ( // Lost indicates that the underlying PersistentVolumeClaim has been lost and the `VirtualDisk` can no longer be used. Lost ReadyReason = "PVCLost" + ResizedReasonUnknown ResizedReason = "Unknown" // ResizingNotRequested indicates that the resize operation has not been requested yet. ResizingNotRequested ResizedReason = "NotRequested" // InProgress indicates that the resize request has been detected and the operation is currently in progress. @@ -77,6 +80,7 @@ const ( // ResizingNotAvailable indicates that the resize operation is not available for now. ResizingNotAvailable SnapshottingReason = "NotAvailable" + SnapshottingReasonUnknown SnapshottingReason = "Unknown" // SnapshottingNotRequested indicates that the snapshotting operation has been successfully started and is in progress now. SnapshottingNotRequested SnapshottingReason = "NotRequested" // Snapshotting indicates that the snapshotting operation has been successfully started and is in progress now. diff --git a/api/core/v1alpha2/vdscondition/condition.go b/api/core/v1alpha2/vdscondition/condition.go index 60842c3bc..da02aaefc 100644 --- a/api/core/v1alpha2/vdscondition/condition.go +++ b/api/core/v1alpha2/vdscondition/condition.go @@ -34,11 +34,13 @@ type ( ) const ( + VirtualDiskReadyReasonUnknown VirtualDiskReadyReason = "Unknown" // VirtualDiskReady signifies that the source virtual disk is ready for snapshotting, allowing the snapshot process to begin. VirtualDiskReady VirtualDiskReadyReason = "VirtualDiskReady" // VirtualDiskNotReadyForSnapshotting signifies that the source virtual disk is not ready for snapshotting, preventing the snapshot process from starting. VirtualDiskNotReadyForSnapshotting VirtualDiskReadyReason = "VirtualDiskNotReadyForSnapshotting" + VirtualDiskSnapshotReadyReasonUnknown VirtualDiskSnapshotReadyReason = "Unknown" // WaitingForTheVirtualDisk signifies that the snapshot process is waiting for the virtual disk to become ready for snapshotting. WaitingForTheVirtualDisk VirtualDiskSnapshotReadyReason = "WaitingForTheVirtualDisk" // PotentiallyInconsistent signifies that the snapshotting process cannot begin because creating a snapshot of virtual disk attached to the running virtual machine might result in an inconsistent snapshot. diff --git a/api/core/v1alpha2/vicondition/condition.go b/api/core/v1alpha2/vicondition/condition.go index 0b3031a68..72ff78386 100644 --- a/api/core/v1alpha2/vicondition/condition.go +++ b/api/core/v1alpha2/vicondition/condition.go @@ -34,6 +34,7 @@ type ( ) const ( + DatasourceReadyReasonUnknown DatasourceReadyReason = "Unknown" // DatasourceReady indicates that the datasource is ready for use, allowing the import process to start. DatasourceReady DatasourceReadyReason = "DatasourceReady" // ContainerRegistrySecretNotFound indicates that the container registry secret was not found, which prevents the import process from starting. @@ -45,6 +46,7 @@ const ( // VirtualDiskNotReady indicates that the `VirtualDisk` datasource is not ready, which prevents the import process from starting. VirtualDiskNotReady DatasourceReadyReason = "VirtualDiskNotReady" + ReadyReasonUnknown ReadyReason = "Unknown" // WaitForUserUpload indicates that the `VirtualImage` is waiting for the user to upload a datasource for the import process to continue. WaitForUserUpload ReadyReason = "WaitForUserUpload" // Provisioning indicates that the provisioning process is currently in progress. diff --git a/api/core/v1alpha2/vmipcondition/condition.go b/api/core/v1alpha2/vmipcondition/condition.go index 8322e22f8..c9b2e263e 100644 --- a/api/core/v1alpha2/vmipcondition/condition.go +++ b/api/core/v1alpha2/vmipcondition/condition.go @@ -47,6 +47,8 @@ func (r AttachedReason) String() string { } const ( + BoundReasonUnknown BoundReason = "Unknown" + // VirtualMachineIPAddressIsOutOfTheValidRange is a BoundReason indicating when specified IP address is out of the range in controller settings. VirtualMachineIPAddressIsOutOfTheValidRange BoundReason = "VirtualMachineIPAddressIsOutOfTheValidRange" @@ -65,6 +67,8 @@ const ( // Bound is a BoundReason indicating the IP address lease is successfully bound. Bound BoundReason = "Bound" + AttachedReasonUnknown AttachedReason = "Unknown" + // VirtualMachineNotFound is an AttachedReason indicating the Virtual Machine was not found. VirtualMachineNotFound AttachedReason = "VirtualMachineNotFound" diff --git a/api/core/v1alpha2/vmiplcondition/condition.go b/api/core/v1alpha2/vmiplcondition/condition.go index a677100f1..f51325ae8 100644 --- a/api/core/v1alpha2/vmiplcondition/condition.go +++ b/api/core/v1alpha2/vmiplcondition/condition.go @@ -35,6 +35,8 @@ func (r BoundReason) String() string { } const ( + BoundReasonUnknown BoundReason = "Unknown" + // Released is a BoundReason indicating the IP address lease has been released. Released BoundReason = "Released" diff --git a/crds/clustervirtualimages.yaml b/crds/clustervirtualimages.yaml index 6683f371e..1ddac679b 100644 --- a/crds/clustervirtualimages.yaml +++ b/crds/clustervirtualimages.yaml @@ -193,36 +193,78 @@ spec: type: object properties: conditions: - description: | - The latest available observations of an object's current state. - type: array + description: + The latest detailed observations of the VirtualMachineOperation + resource. items: - type: object + description: + "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: - lastProbeTime: - description: Last time the condition was checked. - format: date-time - type: string lastTransitionTime: - description: Last time the condition transit from one status to another. + 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: Human readable message indicating details about last transition. + 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: (brief) reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - enum: ["True", "False", "Unknown"] type: - description: Type of condition. + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 + type: array downloadSpeed: type: object description: | diff --git a/crds/virtualdisks.yaml b/crds/virtualdisks.yaml index 20b5131b4..08d4b8a9f 100644 --- a/crds/virtualdisks.yaml +++ b/crds/virtualdisks.yaml @@ -215,36 +215,78 @@ spec: type: object properties: conditions: - description: | - The latest available observations of an object's current state. - type: array + description: + The latest detailed observations of the VirtualMachineOperation + resource. items: - type: object + description: + "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: - lastProbeTime: - description: Last time the condition was checked. - format: date-time - type: string lastTransitionTime: - description: Last time the condition transit from one status to another. + 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: Human readable message indicating details about last transition. + 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: (brief) reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - enum: ["True", "False", "Unknown"] type: - description: Type of condition. + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 + type: array downloadSpeed: type: object description: | diff --git a/crds/virtualdisksnapshots.yaml b/crds/virtualdisksnapshots.yaml index 2df08a445..cddfe21c4 100644 --- a/crds/virtualdisksnapshots.yaml +++ b/crds/virtualdisksnapshots.yaml @@ -61,36 +61,78 @@ spec: type: object properties: conditions: - description: | - The latest available observations of an object's current state. - type: array + description: + The latest detailed observations of the VirtualMachineOperation + resource. items: - type: object + description: + "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: - lastProbeTime: - description: Last time the condition was checked. - format: date-time - type: string lastTransitionTime: - description: Last time the condition transit from one status to another. + 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: Human readable message indicating details about last transition. + 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: (brief) reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - enum: ["True", "False", "Unknown"] type: - description: Type of condition. + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 + type: array volumeSnapshotName: type: string description: | diff --git a/crds/virtualimages.yaml b/crds/virtualimages.yaml index 7b607a92f..02ab0cd73 100644 --- a/crds/virtualimages.yaml +++ b/crds/virtualimages.yaml @@ -196,36 +196,78 @@ spec: type: object properties: conditions: - description: | - The latest available observations of an object's current state. - type: array + description: + The latest detailed observations of the VirtualMachineOperation + resource. items: - type: object + description: + "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: - lastProbeTime: - description: Last time the condition was checked. - format: date-time - type: string lastTransitionTime: - description: Last time the condition transit from one status to another. + 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: Human readable message indicating details about last transition. + 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: (brief) reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - enum: ["True", "False", "Unknown"] type: - description: Type of condition. + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 + type: array downloadSpeed: type: object description: | diff --git a/crds/virtualmachineipaddresses.yaml b/crds/virtualmachineipaddresses.yaml index 76feb7477..974c4fe74 100644 --- a/crds/virtualmachineipaddresses.yaml +++ b/crds/virtualmachineipaddresses.yaml @@ -53,36 +53,78 @@ spec: The observed state of `VirtualMachineIPAddress`. properties: conditions: - description: | - The latest available observations of an object's current state. - type: array + description: + The latest detailed observations of the VirtualMachineOperation + resource. items: - type: object + description: + "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: - lastProbeTime: - description: Last time the condition was checked. - format: date-time - type: string lastTransitionTime: - description: Last time the condition transit from one status to another. + 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: Human readable message indicating details about last transition. + 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: (brief) reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - enum: ["True", "False", "Unknown"] type: - description: Type of condition. + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 + type: array address: description: | The assigned IP address. diff --git a/crds/virtualmachineipaddressleases.yaml b/crds/virtualmachineipaddressleases.yaml index e6b20b79e..f2a326d8e 100644 --- a/crds/virtualmachineipaddressleases.yaml +++ b/crds/virtualmachineipaddressleases.yaml @@ -59,36 +59,78 @@ spec: The observed state of `VirtualMachineIPAddressLease`. properties: conditions: - description: | - The latest available observations of an object's current state. - type: array + description: + The latest detailed observations of the VirtualMachineOperation + resource. items: - type: object + description: + "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: - lastProbeTime: - description: Last time the condition was checked. - format: date-time - type: string lastTransitionTime: - description: Last time the condition transit from one status to another. + 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: Human readable message indicating details about last transition. + 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: (brief) reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string - enum: ["True", "False", "Unknown"] type: - description: Type of condition. + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 + type: array phase: type: string enum: diff --git a/images/virtualization-artifact/pkg/controller/cvi/internal/datasource_ready.go b/images/virtualization-artifact/pkg/controller/cvi/internal/datasource_ready.go index 444758a02..1d0a042fa 100644 --- a/images/virtualization-artifact/pkg/controller/cvi/internal/datasource_ready.go +++ b/images/virtualization-artifact/pkg/controller/cvi/internal/datasource_ready.go @@ -46,6 +46,7 @@ func (h DatasourceReadyHandler) Handle(ctx context.Context, cvi *virtv2.ClusterV condition = metav1.Condition{ Type: cvicondition.DatasourceReadyType, Status: metav1.ConditionUnknown, + Reason: cvicondition.DatasourceReadyReasonUnknown, } } diff --git a/images/virtualization-artifact/pkg/controller/cvi/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/cvi/internal/life_cycle.go index 10dea1b14..082a314d1 100644 --- a/images/virtualization-artifact/pkg/controller/cvi/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/cvi/internal/life_cycle.go @@ -48,6 +48,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, cvi *virtv2.ClusterVirtual readyCondition = metav1.Condition{ Type: cvicondition.ReadyType, Status: metav1.ConditionUnknown, + Reason: cvicondition.ReadyReasonUnknown, } service.SetCondition(readyCondition, &cvi.Status.Conditions) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/datasource_ready.go b/images/virtualization-artifact/pkg/controller/vd/internal/datasource_ready.go index 795a02d68..70b04aa21 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/datasource_ready.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/datasource_ready.go @@ -48,6 +48,7 @@ func (h DatasourceReadyHandler) Handle(ctx context.Context, vd *virtv2.VirtualDi condition = metav1.Condition{ Type: vdcondition.DatasourceReadyType, Status: metav1.ConditionUnknown, + Reason: vdcondition.DatasourceReadyReasonUnknown, } } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vd/internal/life_cycle.go index 5b8134d15..400234475 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/life_cycle.go @@ -53,6 +53,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) (r readyCondition = metav1.Condition{ Type: vdcondition.ReadyType, Status: metav1.ConditionUnknown, + Reason: vdcondition.ReadyReasonUnknown, } service.SetCondition(readyCondition, &vd.Status.Conditions) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go b/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go index b1d863bc2..b1a9dfce7 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go @@ -51,6 +51,7 @@ func (h ResizingHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) (re condition = metav1.Condition{ Type: vdcondition.ResizedType, Status: metav1.ConditionUnknown, + Reason: vdcondition.ResizedReasonUnknown, } } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/snapshotting.go b/images/virtualization-artifact/pkg/controller/vd/internal/snapshotting.go index 629342fa8..e7e5f4ad0 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/snapshotting.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/snapshotting.go @@ -43,6 +43,7 @@ func (h SnapshottingHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) condition = metav1.Condition{ Type: vdcondition.SnapshottingType, Status: metav1.ConditionUnknown, + Reason: vdcondition.SnapshottingReasonUnknown, } } diff --git a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go index 99c121d68..faa400175 100644 --- a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/life_cycle.go @@ -51,6 +51,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vdSnapshot *virtv2.Virtual condition = metav1.Condition{ Type: vdscondition.VirtualDiskSnapshotReadyType, Status: metav1.ConditionUnknown, + Reason: vdscondition.VirtualDiskSnapshotReadyReasonUnknown, } } diff --git a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/virtual_disk_ready.go b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/virtual_disk_ready.go index b1094e7a0..df08b3115 100644 --- a/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/virtual_disk_ready.go +++ b/images/virtualization-artifact/pkg/controller/vdsnapshot/internal/virtual_disk_ready.go @@ -45,6 +45,7 @@ func (h VirtualDiskReadyHandler) Handle(ctx context.Context, vdSnapshot *virtv2. condition = metav1.Condition{ Type: vdscondition.VirtualDiskReadyType, Status: metav1.ConditionUnknown, + Reason: vdscondition.VirtualDiskReadyReasonUnknown, } } diff --git a/images/virtualization-artifact/pkg/controller/vi/internal/datasource_ready.go b/images/virtualization-artifact/pkg/controller/vi/internal/datasource_ready.go index 9d11ed922..5bc53e9fa 100644 --- a/images/virtualization-artifact/pkg/controller/vi/internal/datasource_ready.go +++ b/images/virtualization-artifact/pkg/controller/vi/internal/datasource_ready.go @@ -47,6 +47,7 @@ func (h DatasourceReadyHandler) Handle(ctx context.Context, vi *virtv2.VirtualIm condition = metav1.Condition{ Type: vicondition.DatasourceReadyType, Status: metav1.ConditionUnknown, + Reason: vicondition.DatasourceReadyReasonUnknown, } } diff --git a/images/virtualization-artifact/pkg/controller/vi/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vi/internal/life_cycle.go index 4b1004d2c..32ec4f551 100644 --- a/images/virtualization-artifact/pkg/controller/vi/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vi/internal/life_cycle.go @@ -48,6 +48,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vi *virtv2.VirtualImage) ( readyCondition = metav1.Condition{ Type: vicondition.ReadyType, Status: metav1.ConditionUnknown, + Reason: vicondition.ReadyReasonUnknown, } service.SetCondition(readyCondition, &vi.Status.Conditions) diff --git a/images/virtualization-artifact/pkg/controller/vmip/internal/iplease_handler.go b/images/virtualization-artifact/pkg/controller/vmip/internal/iplease_handler.go index 1ecdb1585..bf77a8b0f 100644 --- a/images/virtualization-artifact/pkg/controller/vmip/internal/iplease_handler.go +++ b/images/virtualization-artifact/pkg/controller/vmip/internal/iplease_handler.go @@ -134,31 +134,26 @@ func (h IPLeaseHandler) createNewLease(ctx context.Context, state state.VMIPStat msg := fmt.Sprintf("the VirtualMachineIP cannot be created: %s", err.Error()) log.Info(msg) - //nolint:staticcheck - mgr := conditions.NewManager(vmipStatus.Conditions) conditionBound := conditions.NewConditionBuilder(vmipcondition.BoundType). Generation(vmip.GetGeneration()) switch { case errors.Is(err, service.ErrIPAddressOutOfRange): vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending - mgr.Update(conditionBound.Status(metav1.ConditionFalse). + conditionBound.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineIPAddressIsOutOfTheValidRange). Message(fmt.Sprintf("The requested address %s is out of the valid range", - vmip.Spec.StaticIP)). - Condition()) + vmip.Spec.StaticIP)) h.recorder.Event(vmip, corev1.EventTypeWarning, vmipcondition.VirtualMachineIPAddressIsOutOfTheValidRange.String(), msg) case errors.Is(err, service.ErrIPAddressAlreadyExist): vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending - mgr.Update(conditionBound.Status(metav1.ConditionFalse). + conditionBound.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists). Message(fmt.Sprintf("VirtualMachineIPAddressLease %s is bound to another VirtualMachineIPAddress", - common.IpToLeaseName(vmipStatus.Address))). - Condition()) + common.IpToLeaseName(vmipStatus.Address))) h.recorder.Event(vmip, corev1.EventTypeWarning, vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists.String(), msg) } - - vmipStatus.Conditions = mgr.Generate() + conditions.SetCondition(conditionBound, &vmipStatus.Conditions) return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vmip/internal/lifecycle_handler.go b/images/virtualization-artifact/pkg/controller/vmip/internal/lifecycle_handler.go index d96f9f7e3..59f78a7d4 100644 --- a/images/virtualization-artifact/pkg/controller/vmip/internal/lifecycle_handler.go +++ b/images/virtualization-artifact/pkg/controller/vmip/internal/lifecycle_handler.go @@ -52,20 +52,26 @@ func (h *LifecycleHandler) Handle(ctx context.Context, state state.VMIPState) (r return reconcile.Result{}, err } - //nolint:staticcheck - mgr := conditions.NewManager(vmipStatus.Conditions) conditionBound := conditions.NewConditionBuilder(vmipcondition.BoundType). - Generation(vmip.GetGeneration()) + Generation(vmip.GetGeneration()). + Reason(vmipcondition.BoundReasonUnknown). + Status(metav1.ConditionUnknown) conditionAttach := conditions.NewConditionBuilder(vmipcondition.AttachedType). - Generation(vmip.GetGeneration()) + Generation(vmip.GetGeneration()). + Reason(vmipcondition.AttachedReasonUnknown). + Status(metav1.ConditionUnknown) + + defer func() { + conditions.SetCondition(conditionBound, &vmipStatus.Conditions) + conditions.SetCondition(conditionAttach, &vmipStatus.Conditions) + }() if vm == nil || vm.DeletionTimestamp != nil { vmipStatus.VirtualMachine = "" - mgr.Update(conditionAttach.Status(metav1.ConditionFalse). + conditionAttach.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineNotFound). - Message("Virtual machine not found"). - Condition()) + Message("Virtual machine not found") } lease, err := state.VirtualMachineIPLease(ctx) @@ -78,38 +84,34 @@ func (h *LifecycleHandler) Handle(ctx context.Context, state state.VMIPState) (r case lease == nil && vmipStatus.Address != "": if vmipStatus.Phase != virtv2.VirtualMachineIPAddressPhasePending { vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending - mgr.Update(conditionBound.Status(metav1.ConditionFalse). + conditionBound.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineIPAddressLeaseLost). Message(fmt.Sprintf("VirtualMachineIPAddressLease %s doesn't exist", - common.IpToLeaseName(vmipStatus.Address))). - Condition()) + common.IpToLeaseName(vmipStatus.Address))) } case lease == nil: if vmipStatus.Phase != virtv2.VirtualMachineIPAddressPhasePending { vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending - mgr.Update(conditionBound.Status(metav1.ConditionFalse). + conditionBound.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineIPAddressLeaseNotFound). - Message("VirtualMachineIPAddressLease is not found"). - Condition()) + Message("VirtualMachineIPAddressLease is not found") } case vm != nil && vm.GetDeletionTimestamp().IsZero(): if vmipStatus.Phase != virtv2.VirtualMachineIPAddressPhaseAttached { vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhaseAttached vmipStatus.VirtualMachine = vm.Name - mgr.Update(conditionAttach.Status(metav1.ConditionTrue). - Reason(vmipcondition.Attached). - Condition()) + conditionAttach.Status(metav1.ConditionTrue). + Reason(vmipcondition.Attached) } case util.IsBoundLease(lease, vmip): if vmipStatus.Phase != virtv2.VirtualMachineIPAddressPhaseBound { vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhaseBound vmipStatus.Address = common.LeaseNameToIP(lease.Name) - mgr.Update(conditionBound.Status(metav1.ConditionTrue). - Reason(vmipcondition.Bound). - Condition()) + conditionBound.Status(metav1.ConditionTrue). + Reason(vmipcondition.Bound) } case lease.Status.Phase == virtv2.VirtualMachineIPAddressLeasePhaseBound: @@ -117,36 +119,33 @@ func (h *LifecycleHandler) Handle(ctx context.Context, state state.VMIPState) (r vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending log.Warn(fmt.Sprintf("VirtualMachineIPAddressLease %s is bound to another VirtualMachineIPAddress resource: %s/%s", lease.Name, lease.Spec.VirtualMachineIPAddressRef.Name, lease.Spec.VirtualMachineIPAddressRef.Namespace)) - mgr.Update(conditionBound.Status(metav1.ConditionFalse). + conditionBound.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists). Message(fmt.Sprintf("VirtualMachineIPAddressLease %s is bound to another VirtualMachineIPAddress resource", - lease.Name)). - Condition()) + lease.Name)) } case lease.Spec.VirtualMachineIPAddressRef.Namespace != vmip.Namespace: if vmipStatus.Phase != virtv2.VirtualMachineIPAddressPhasePending { vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending - mgr.Update(conditionBound.Status(metav1.ConditionFalse). + conditionBound.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineIPAddressLeaseAlreadyExists). - Message(fmt.Sprintf("The VirtualMachineIPLease %s belongs to a different namespace", lease.Name)). - Condition()) + Message(fmt.Sprintf("The VirtualMachineIPLease %s belongs to a different namespace", lease.Name)) } needRequeue = true default: if vmipStatus.Phase != virtv2.VirtualMachineIPAddressPhasePending { vmipStatus.Phase = virtv2.VirtualMachineIPAddressPhasePending - mgr.Update(conditionBound.Status(metav1.ConditionFalse). + conditionBound.Status(metav1.ConditionFalse). Reason(vmipcondition.VirtualMachineIPAddressLeaseNotReady). Message(fmt.Sprintf("VirtualMachineIPAddressLease %s is not ready", - lease.Name)). - Condition()) + lease.Name)) } } - log.Info("Set VirtualMachineIP phase", "phase", vmipStatus.Phase) - vmipStatus.Conditions = mgr.Generate() + log.Debug("Set VirtualMachineIP phase", "phase", vmipStatus.Phase) + vmipStatus.ObservedGeneration = vmip.GetGeneration() if !needRequeue { return reconcile.Result{}, nil diff --git a/images/virtualization-artifact/pkg/controller/vmiplease/internal/lifecycle_handler.go b/images/virtualization-artifact/pkg/controller/vmiplease/internal/lifecycle_handler.go index ee8df1d9e..b54a6222a 100644 --- a/images/virtualization-artifact/pkg/controller/vmiplease/internal/lifecycle_handler.go +++ b/images/virtualization-artifact/pkg/controller/vmiplease/internal/lifecycle_handler.go @@ -45,10 +45,14 @@ func (h *LifecycleHandler) Handle(ctx context.Context, state state.VMIPLeaseStat return reconcile.Result{}, nil } - //nolint:staticcheck - mgr := conditions.NewManager(leaseStatus.Conditions) cb := conditions.NewConditionBuilder(vmiplcondition.BoundType). - Generation(lease.GetGeneration()) + Generation(lease.GetGeneration()). + Reason(vmiplcondition.BoundReasonUnknown). + Status(metav1.ConditionUnknown) + + defer func() { + conditions.SetCondition(cb, &leaseStatus.Conditions) + }() vmip, err := state.VirtualMachineIPAddress(ctx) if err != nil { @@ -58,21 +62,18 @@ func (h *LifecycleHandler) Handle(ctx context.Context, state state.VMIPLeaseStat if vmip != nil { if leaseStatus.Phase != virtv2.VirtualMachineIPAddressLeasePhaseBound { leaseStatus.Phase = virtv2.VirtualMachineIPAddressLeasePhaseBound - mgr.Update(cb.Status(metav1.ConditionTrue). - Reason(vmiplcondition.Bound). - Condition()) + cb.Status(metav1.ConditionTrue). + Reason(vmiplcondition.Bound) } } else { if leaseStatus.Phase != virtv2.VirtualMachineIPAddressLeasePhaseReleased { leaseStatus.Phase = virtv2.VirtualMachineIPAddressLeasePhaseReleased - mgr.Update(cb.Status(metav1.ConditionFalse). + cb.Status(metav1.ConditionFalse). Reason(vmiplcondition.Released). - Message("VirtualMachineIPAddress lease is not used by any VirtualMachineIPAddress"). - Condition()) + Message("VirtualMachineIPAddress lease is not used by any VirtualMachineIPAddress") } } - leaseStatus.Conditions = mgr.Generate() leaseStatus.ObservedGeneration = lease.GetGeneration() return reconcile.Result{}, nil