kn depends on Knative serving and eventing and supports different versions of Knative installed on the server-side. For the sake of this discussion, let stick to Knative serving first as the Knative eventing dependency can be tackled the same.
There are essentially two scenarios when the Knative serving version that is used as a compile-time dependency for kn and the actual serving version running on a cluster differs:
kn is used for a newer cluster side version of Knative serving which is not yet known to the time when this version of kn has been released.
kn is used for an older version of Knative Serving which does not support the latest API version of the Serving dependency kn is compiled with.
Both those scenarios should be possible to some extent, much a bit like kubectl works with older and newer Kubernetes clusters.
As a single Knative serving release supports multiple API version endpoints (which are converted on the fly, e.g. Serving 0.10.0 supports v1alpha1, v1beta1 and v1), there are two general strategies to maximize the overlap of support for newer and older versions of Knative serving:
Defensive Strategy
kn use the latest available Serving release as a compile dependency (e.g. knative-serving v0.10.0), but uses the oldest supported API version for the types used in the KnServingClient interface and as endpoint when calling a cluster. I.e. for a compile dependency to knative-serving v0.10.0 this would be v1alpha1. Ideally kn queries the Knative Serving CRD from the cluster during runtime and verifies that the selected API version (v1alpha1 in this example) is supported. If not, stop with an error that the Knative serving it too new and not supported for this version of kn, so that the user has to upgrade kn to a newer version of kn.
Pro
- Simpler to implement (no API object conversions needed in the implementation of
KnServingClient)
Con
- A given
kn can be easily outdated by newer versions of Knative Serving. E.g. when Knative serving v0.11.0 (or v1.0.0) decides to drop v1alpha1 support, kn 0.9.0 can't be used anymore and the newest kn version, aligned with the latest serving version as compile dependency needs to be used.
Optimistic Strategy
kn uses the latest available Serving release as a compile dependency but uses the newest supported API version. E.g. for knative-serving v0.10.0 this would be v1. Again, kn should query the server-side for the Serving CRD and check if this newest API version is supported. If this is not the case, the next-newest version (e.g. v1beta1) should be checked and so on. kn's KnServingClient interface should use the newest API objects (v1) but its implementation transparently converts to older versions (v1beta1, v1alpha) depending on the maximally supported API version on the server-side (and then used different API endpoints when talking to the server). This goes down up to the minimal version supported by the selected compile-time dependency.
Pro
- Much longer support for newer, not-yet-released, versions of Knative serving (as it's supposed that the newest API version (v1) is supported much longer than the oldest (v1alpha1))
- Support for older API versions like in the "Defensive Approach"
Con
- More complex to implement as there needs to be added conversion code for the supported API versions (
v1, v1beta1, v1alpha1), much like the Serving operators need to convert different API version objects to the CR's storage version. Actually, one could even 'borrow' code from the server-side (at least to find out what needs to be converted). However, the conversion is very likely the other way round (from newer to older).
For short term (e.g. kn version 0.9.0 and 0.10.0) I think the "Defensive Strategy" is more suitable as it does not need any code changes on the client-side (except maybe the server-side API version detection by querying the serving CRD). However long-term (post 0.10.0), the "Optimistic Strategy" seems to be more suitable as it allows for a larger version overlap between client and server.
Notes:
- This proposal assumes that API versions are stable. This is not necessarily the case for alpha versions (and indeed,
v1alpha1 has been changed itself between different releases of serving), but as this proposal is more about a long-term strategy and the hope is, that v1alpha1 is not touched anymore anyway (and v1beta1 and v1 are indeed stable), this aspect is omitted in this discussion (which also would make it much more difficult as there is no way to query from a CRD "which" alpha version actually is meant and one would have to over the knative-serving release version, but this is not easily exposed to the client from a given cluster)
- Knative eventing has a different API version release cycles, so
KnEventingClients could adopt a different strategy than for serving.
kndepends on Knative serving and eventing and supports different versions of Knative installed on the server-side. For the sake of this discussion, let stick to Knative serving first as the Knative eventing dependency can be tackled the same.There are essentially two scenarios when the Knative serving version that is used as a compile-time dependency for
knand the actual serving version running on a cluster differs:knis used for a newer cluster side version of Knative serving which is not yet known to the time when this version ofknhas been released.knis used for an older version of Knative Serving which does not support the latest API version of the Serving dependencyknis compiled with.Both those scenarios should be possible to some extent, much a bit like
kubectlworks with older and newer Kubernetes clusters.As a single Knative serving release supports multiple API version endpoints (which are converted on the fly, e.g. Serving 0.10.0 supports
v1alpha1,v1beta1andv1), there are two general strategies to maximize the overlap of support for newer and older versions of Knative serving:Defensive Strategy
knuse the latest available Serving release as a compile dependency (e.g. knative-serving v0.10.0), but uses the oldest supported API version for the types used in theKnServingClientinterface and as endpoint when calling a cluster. I.e. for a compile dependency to knative-serving v0.10.0 this would bev1alpha1. Ideallyknqueries the Knative Serving CRD from the cluster during runtime and verifies that the selected API version (v1alpha1in this example) is supported. If not, stop with an error that the Knative serving it too new and not supported for this version ofkn, so that the user has to upgradeknto a newer version ofkn.Pro
KnServingClient)Con
kncan be easily outdated by newer versions of Knative Serving. E.g. when Knative serving v0.11.0 (or v1.0.0) decides to dropv1alpha1support,kn 0.9.0can't be used anymore and the newestknversion, aligned with the latest serving version as compile dependency needs to be used.Optimistic Strategy
knuses the latest available Serving release as a compile dependency but uses the newest supported API version. E.g. forknative-serving v0.10.0this would bev1. Again, kn should query the server-side for the Serving CRD and check if this newest API version is supported. If this is not the case, the next-newest version (e.g.v1beta1) should be checked and so on. kn'sKnServingClientinterface should use the newest API objects (v1) but its implementation transparently converts to older versions (v1beta1,v1alpha) depending on the maximally supported API version on the server-side (and then used different API endpoints when talking to the server). This goes down up to the minimal version supported by the selected compile-time dependency.Pro
Con
v1,v1beta1,v1alpha1), much like the Serving operators need to convert different API version objects to the CR's storage version. Actually, one could even 'borrow' code from the server-side (at least to find out what needs to be converted). However, the conversion is very likely the other way round (from newer to older).For short term (e.g.
knversion 0.9.0 and 0.10.0) I think the "Defensive Strategy" is more suitable as it does not need any code changes on the client-side (except maybe the server-side API version detection by querying the serving CRD). However long-term (post 0.10.0), the "Optimistic Strategy" seems to be more suitable as it allows for a larger version overlap between client and server.Notes:
v1alpha1has been changed itself between different releases of serving), but as this proposal is more about a long-term strategy and the hope is, that v1alpha1 is not touched anymore anyway (and v1beta1 and v1 are indeed stable), this aspect is omitted in this discussion (which also would make it much more difficult as there is no way to query from a CRD "which" alpha version actually is meant and one would have to over the knative-serving release version, but this is not easily exposed to the client from a given cluster)KnEventingClients could adopt a different strategy than for serving.