|
14 | 14 | import io.javaoperatorsdk.operator.api.reconciler.Context;
|
15 | 15 | import io.javaoperatorsdk.operator.api.reconciler.DefaultContext;
|
16 | 16 | import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
|
| 17 | +import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; |
17 | 18 | import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
|
18 | 19 | import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
|
19 | 20 |
|
@@ -109,27 +110,76 @@ private PostExecutionControl<R> handleCreateOrUpdate(
|
109 | 110 | updateCustomResourceWithFinalizer(resource);
|
110 | 111 | return PostExecutionControl.onlyFinalizerAdded();
|
111 | 112 | } else {
|
112 |
| - log.debug( |
113 |
| - "Executing createOrUpdate for resource {} with version: {} with execution scope: {}", |
114 |
| - getName(resource), |
115 |
| - getVersion(resource), |
116 |
| - executionScope); |
| 113 | + try { |
| 114 | + var resourceForExecution = |
| 115 | + cloneResourceForErrorStatusHandlerIfNeeded(resource, context); |
| 116 | + return createOrUpdateExecution(executionScope, resourceForExecution, context); |
| 117 | + } catch (RuntimeException e) { |
| 118 | + handleLastAttemptErrorStatusHandler(resource, context, e); |
| 119 | + throw e; |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + /** |
| 125 | + * Resource make sense only to clone for the ErrorStatusHandler. Otherwise, this operation can be |
| 126 | + * skipped since it can be memory and time-consuming. However, it needs to be cloned since it's |
| 127 | + * common that the custom resource is changed during an execution, and it's much cleaner to have |
| 128 | + * to original resource in place for status update. |
| 129 | + */ |
| 130 | + private R cloneResourceForErrorStatusHandlerIfNeeded(R resource, Context context) { |
| 131 | + if (isLastAttemptOfRetryAndErrorStatusHandlerPresent(context)) { |
| 132 | + return controller.getConfiguration().getConfigurationService().getResourceCloner() |
| 133 | + .clone(resource); |
| 134 | + } else { |
| 135 | + return resource; |
| 136 | + } |
| 137 | + } |
117 | 138 |
|
118 |
| - UpdateControl<R> updateControl = controller.reconcile(resource, context); |
119 |
| - R updatedCustomResource = null; |
120 |
| - if (updateControl.isUpdateCustomResourceAndStatusSubResource()) { |
121 |
| - updatedCustomResource = updateCustomResource(updateControl.getCustomResource()); |
122 |
| - updateControl |
123 |
| - .getCustomResource() |
124 |
| - .getMetadata() |
125 |
| - .setResourceVersion(updatedCustomResource.getMetadata().getResourceVersion()); |
126 |
| - updatedCustomResource = updateStatusGenerationAware(updateControl.getCustomResource()); |
127 |
| - } else if (updateControl.isUpdateStatusSubResource()) { |
128 |
| - updatedCustomResource = updateStatusGenerationAware(updateControl.getCustomResource()); |
129 |
| - } else if (updateControl.isUpdateCustomResource()) { |
130 |
| - updatedCustomResource = updateCustomResource(updateControl.getCustomResource()); |
| 139 | + private PostExecutionControl<R> createOrUpdateExecution(ExecutionScope<R> executionScope, |
| 140 | + R resource, Context context) { |
| 141 | + log.debug( |
| 142 | + "Executing createOrUpdate for resource {} with version: {} with execution scope: {}", |
| 143 | + getName(resource), |
| 144 | + getVersion(resource), |
| 145 | + executionScope); |
| 146 | + |
| 147 | + UpdateControl<R> updateControl = controller.reconcile(resource, context); |
| 148 | + R updatedCustomResource = null; |
| 149 | + if (updateControl.isUpdateCustomResourceAndStatusSubResource()) { |
| 150 | + updatedCustomResource = updateCustomResource(updateControl.getCustomResource()); |
| 151 | + updateControl |
| 152 | + .getCustomResource() |
| 153 | + .getMetadata() |
| 154 | + .setResourceVersion(updatedCustomResource.getMetadata().getResourceVersion()); |
| 155 | + updatedCustomResource = updateStatusGenerationAware(updateControl.getCustomResource()); |
| 156 | + } else if (updateControl.isUpdateStatusSubResource()) { |
| 157 | + updatedCustomResource = updateStatusGenerationAware(updateControl.getCustomResource()); |
| 158 | + } else if (updateControl.isUpdateCustomResource()) { |
| 159 | + updatedCustomResource = updateCustomResource(updateControl.getCustomResource()); |
| 160 | + } |
| 161 | + return createPostExecutionControl(updatedCustomResource, updateControl); |
| 162 | + } |
| 163 | + |
| 164 | + private void handleLastAttemptErrorStatusHandler(R resource, Context context, |
| 165 | + RuntimeException e) { |
| 166 | + if (isLastAttemptOfRetryAndErrorStatusHandlerPresent(context)) { |
| 167 | + try { |
| 168 | + var updatedResource = ((ErrorStatusHandler<R>) controller.getReconciler()) |
| 169 | + .updateErrorStatus(resource, e); |
| 170 | + customResourceFacade.updateStatus(updatedResource); |
| 171 | + } catch (RuntimeException ex) { |
| 172 | + log.error("Error during error status handling.", ex); |
131 | 173 | }
|
132 |
| - return createPostExecutionControl(updatedCustomResource, updateControl); |
| 174 | + } |
| 175 | + } |
| 176 | + |
| 177 | + private boolean isLastAttemptOfRetryAndErrorStatusHandlerPresent(Context context) { |
| 178 | + if (context.getRetryInfo().isPresent()) { |
| 179 | + return context.getRetryInfo().get().isLastAttempt() |
| 180 | + && controller.getReconciler() instanceof ErrorStatusHandler; |
| 181 | + } else { |
| 182 | + return false; |
133 | 183 | }
|
134 | 184 | }
|
135 | 185 |
|
|
0 commit comments