diff --git a/docs/_data/sidebar.yml b/docs/_data/sidebar.yml index 6fc326ef0b..d2572f5734 100644 --- a/docs/_data/sidebar.yml +++ b/docs/_data/sidebar.yml @@ -9,7 +9,7 @@ url: /docs/glossary - title: Features url: /docs/features - - title: Dependent Resource Feature + - title: Dependent Resources url: /docs/dependent-resources - title: Workflows url: /docs/workflows @@ -26,4 +26,8 @@ - title: Migrating from v2 to v3 url: /docs/v3-migration - title: Migrating from v3 to v3.1 - url: /docs/v3-1-migration \ No newline at end of file + url: /docs/v3-1-migration + - title: Migrating from v4.2 to v4.3 + url: /docs/v4-3-migration + - title: Migrating from v4.3 to v4.4 + url: /docs/v4-4-migration \ No newline at end of file diff --git a/docs/documentation/v4-4-migration.md b/docs/documentation/v4-4-migration.md new file mode 100644 index 0000000000..f6dcf2534e --- /dev/null +++ b/docs/documentation/v4-4-migration.md @@ -0,0 +1,76 @@ +--- +title: Migrating from v4.3 to v4.4 +description: Migrating from v4.3 to v4.4 +layout: docs +permalink: /docs/v4-4-migration +--- + +# Migrating from v4.3 to v4.4 + +## API changes + +### ConfigurationService + +We have simplified how to deal with the Kubernetes client. Previous versions provided direct +access to underlying aspects of the client's configuration or serialization mechanism. However, +the link between these aspects wasn't as explicit as it should have been. Moreover, the Fabric8 +client framework has also revised their serialization architecture in the 6.7 version (see [this +fabric8 pull request](https://github.com/fabric8io/kubernetes-client/pull/4662) for a discussion of +that change), moving from statically configured serialization to a per-client configuration +(though it's still possible to share serialization mechanism between client instances). As a +consequence, we made the following changes to the `ConfigurationService` API: + +- Replaced `getClientConfiguration` and `getObjectMapper` methods by a new `getKubernetesClient` + method: instead of providing the configuration and mapper, you now provide a client instance + configured according to your needs and the SDK will extract the needed information from it + +If you had previously configured a custom configuration or `ObjectMapper`, it is now recommended +that you do so when creating your client instance, as follows, usually using +`ConfigurationServiceOverrider.withKubernetesClient`: + +```java + +class Example { + + public static void main(String[] args) { + Config config; // your configuration + ObjectMapper mapper; // your mapper + final var operator = new Operator(overrider -> overrider.withKubernetesClient( + new KubernetesClientBuilder() + .withConfig(config) + .withKubernetesSerialization(new KubernetesSerialization(mapper, true)) + .build() + )); + } +} +``` + +Consequently, it is now recommended to get the client instance from the `ConfigurationService`. + +### Operator + +It is now recommended to configure your Operator instance by using a +`ConfigurationServiceOverrider` when creating it. This allows you to change the default +configuration values as needed. In particular, instead of passing a Kubernetes client instance +explicitly to the Operator constructor, it is now recommended to provide that value using +`ConfigurationServiceOverrider.withKubernetesClient` as shown above. + +## Using Server-Side Apply in Dependent Resources + +From this version by +default [Dependent Resources](https://javaoperatorsdk.io/docs/dependent-resources) use +[Server Side Apply (SSA)](https://kubernetes.io/docs/reference/using-api/server-side-apply/) to +create and +update Kubernetes resources. A +new [default matching](https://github.com/java-operator-sdk/java-operator-sdk/blob/e95f9c8a8b8a8561c9a735e60fc5d82b7758df8e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java#L163-L163) +algorithm is provided for `KubernetesDependentResource` that is based on `managedFields` of SSA. For +details +see [SSABasedGenericKubernetesResourceMatcher](https://github.com/java-operator-sdk/java-operator-sdk/blob/e95f9c8a8b8a8561c9a735e60fc5d82b7758df8e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java) + +Since those features are hard to completely test, we provided feature flags to revert to the +legacy behavior if needed, +see those +in [ConfigurationService](https://github.com/java-operator-sdk/java-operator-sdk/blob/e95f9c8a8b8a8561c9a735e60fc5d82b7758df8e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L268-L289) + +Note that it is possible to override the related methods/behavior on class level when extending +the `KubernetesDependentResource`. diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java index 2381d46701..3fc01e1f64 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java @@ -67,16 +67,13 @@ public Operator(Consumer overrider) { } /** - * Note that Operator by default closes the client on stop, this can be changed using - * {@link ConfigurationService} - * * @param client client to use to all Kubernetes related operations * @param overrider a {@link ConfigurationServiceOverrider} consumer used to override the default * {@link ConfigurationService} values * @deprecated Use {@link Operator#Operator(Consumer)} instead, passing your custom client with * {@link ConfigurationServiceOverrider#withKubernetesClient(KubernetesClient)} */ - @Deprecated + @Deprecated(since = "4.4.0") public Operator(KubernetesClient client, Consumer overrider) { this(initConfigurationService(client, overrider)); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index 325b547e8f..5beb19aa17 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -42,9 +42,12 @@ public interface ConfigurationService { /** - * Used to clone custom resources. It is strongly suggested that implementors override this method - * since the default implementation creates a new {@link Cloner} instance each time this method is - * called. + * Used to clone custom resources. + * + *

+ * NOTE: It is strongly suggested that implementors override this method since the + * default implementation creates a new {@link Cloner} instance each time this method is called. + *

* * @return the configured {@link Cloner} */ @@ -57,6 +60,32 @@ public R clone(R object) { }; } + /** + * Provides the fully configured {@link KubernetesClient} to use for controllers to the target + * cluster. Note that this client only needs to be able to connect to the cluster, the SDK will + * take care of creating the required connections to watch the target resources (in particular, + * you do not need to worry about setting the namespace information in most cases). + * + *

+ * Previous versions of this class provided direct access to the serialization mechanism (via + * {@link com.fasterxml.jackson.databind.ObjectMapper}) or the client's configuration. This was + * somewhat confusing, in particular with respect to changes made in the Fabric8 client + * serialization architecture made in 6.7. The proper way to configure these aspects is now to + * configure the Kubernetes client accordingly and the SDK will extract the information it needs + * from this instance. The recommended way to do so is to create your operator with + * {@link io.javaoperatorsdk.operator.Operator#Operator(Consumer)}, passing your custom instance + * with {@link ConfigurationServiceOverrider#withKubernetesClient(KubernetesClient)}. + *

+ * + *

+ * NOTE: It is strongly suggested that implementors override this method since the + * default implementation creates a new {@link KubernetesClient} instance each time this method is + * called. + *

+ * + * @return the configured {@link KubernetesClient} + * @since 4.4.0 + */ default KubernetesClient getKubernetesClient() { return new KubernetesClientBuilder() .withConfig(new ConfigBuilder(Config.autoConfigure(null)) @@ -242,6 +271,25 @@ default ResourceClassResolver getResourceClassResolver() { return new DefaultResourceClassResolver(); } + /** + * Creates a new {@link ConfigurationService} instance used to configure an + * {@link io.javaoperatorsdk.operator.Operator} instance, starting from the specified base + * configuration and overriding specific aspects according to the provided + * {@link ConfigurationServiceOverrider} instance. + * + *

+ * NOTE: This overriding mechanism should only be used before creating + * your Operator instance as the configuration service is set at creation time and cannot be + * subsequently changed. As a result, overriding values this way after the Operator has been + * configured will not take effect. + *

+ * + * @param baseConfiguration the {@link ConfigurationService} to start from + * @param overrider the {@link ConfigurationServiceOverrider} used to change the values provided + * by the base configuration + * @return a new {@link ConfigurationService} starting from the configuration provided as base but + * with overridden values. + */ static ConfigurationService newOverriddenConfigurationService( ConfigurationService baseConfiguration, Consumer overrider) { @@ -253,6 +301,25 @@ static ConfigurationService newOverriddenConfigurationService( return baseConfiguration; } + /** + * Creates a new {@link ConfigurationService} instance used to configure an + * {@link io.javaoperatorsdk.operator.Operator} instance, starting from the default configuration + * and overriding specific aspects according to the provided {@link ConfigurationServiceOverrider} + * instance. + * + *

+ * NOTE: This overriding mechanism should only be used before creating + * your Operator instance as the configuration service is set at creation time and cannot be + * subsequently changed. As a result, overriding values this way after the Operator has been + * configured will not take effect. + *

+ * + * @param overrider the {@link ConfigurationServiceOverrider} used to change the values provided + * by the default configuration + * @return a new {@link ConfigurationService} overriding the default values with the ones provided + * by the specified {@link ConfigurationServiceOverrider} + * @since 4.4.0 + */ static ConfigurationService newOverriddenConfigurationService( Consumer overrider) { return newOverriddenConfigurationService(new BaseConfigurationService(), overrider); @@ -269,6 +336,8 @@ default ExecutorServiceManager getExecutorServiceManager() { * Server-Side * Apply (SSA) by default. Note that the legacy approach, and this setting, might be removed * in the future. + * + * @since 4.4.0 */ default boolean ssaBasedCreateUpdateForDependentResources() { return true; @@ -280,6 +349,8 @@ default boolean ssaBasedCreateUpdateForDependentResources() { * Dependent Resources which is quite complex. As a consequence, we introduced this setting to * allow folks to revert to the previous matching algorithm if needed. Note, however, that the * legacy algorithm, and this setting, might be removed in the future. + * + * @since 4.4.0 */ default boolean ssaBasedDefaultMatchingForDependentResources() { return true; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java index e8ad632c95..f66f648a1f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java @@ -105,6 +105,13 @@ public ConfigurationServiceOverrider withWorkflowExecutorService( return this; } + /** + * Replaces the default {@link KubernetesClient} instance by the specified one. This is the + * preferred mechanism to configure which client will be used to access the cluster. + * + * @param client the fully configured client to use for cluster access + * @return this {@link ConfigurationServiceOverrider} for chained customization + */ public ConfigurationServiceOverrider withKubernetesClient(KubernetesClient client) { this.client = client; return this;