Skip to content

Instantly share code, notes, and snippets.

@munnerz
Created May 23, 2019 23:24
Show Gist options
  • Save munnerz/319013fe437dfc35d7234e693a01328a to your computer and use it in GitHub Desktop.
Save munnerz/319013fe437dfc35d7234e693a01328a to your computer and use it in GitHub Desktop.
API structure comments:
- constants package is an implicit part of our API, whether we want it to be or not
- right now, there is an undisclosed dependency between v1alpha{2,3} + internal + constants
- therefore, each of v1alpha2 & 3 should have their own copies of each node role type for example (to allow for migrations in future)
- has a big effect on kind as a library. Should consumers depend on the internal type? Or the external types?
- we don't provide any guarantees on the stability of the *internal type*. It is used simply as a base for conversion
- I am not sure what kubeadm's strategy for this is, however I suspect that there is not a particular good one just yet
- external types are *designed* to be stable and consumed by users, be that via CLI or library
- internal types are meant to be used *only* as a base for conversion, and in order to facilitate new API versions, may change without notice. This makes them inappropriate to be consumed by end users.
I personally think kind (as a binary) should consume *external types* only. The 'LoadConfig' method should be refactored to be LoadConfig(string, runtime.Object), where runtime.Object is *some version of* the kind config. If there is no suitable conversion registered between the config file that the user provides on disk and the config structure that the developer/consumer of the library uses, the machinery will automatically 'bail out' and fail the conversion (which is expected! this implies a user is using a newer version of the kind config with an older version of the lib, so it *is* impossible to convert)
To do this will require kind itself to switch to consuming *external* API versions, and this explains why all kubernetes controllers *also* depend on external versions (despite internal versions being a convinient basis to depend upon)
Tiny proposal:
- If we have the exported methods accept a runtime.Object, they themselves can convert into the *internal* type.
- Kind can internally (in the 'internal' packages) accept an *internal* Cluster object.
- This will allow kind's implementation to be fairly stable, and pushes the complexity of managing multiple API versions into the conversion package (where it *should* live).
- The downside here is that users see `runtime.Object` as an argument for their `Create` calls when consuming kind as a library, which is not so ideal.
- The only real way to work around this in golang is to have `VXalphaY` variants of each public API call, which works fairly nicely and is easy to maintain, despite being slightly abnormal
Closing remarks:
- I think this is most relevant when you view 'kind as a library' as an important piece. Personally, I think a separation between the CLI and the lib like this is probably a good direction as it encourages users to consume kind as a library (we place the same restraints on ourselves as we do CLI users).
- The need for kind as a library has been evidence by kinder as well as during our talks today
- The refactoring work for this is not actually too significant. It will mostly involve changing function signatures and adding in some calls to a Convert function in the public API surface.
- End result is that users don't need to think about anything, and as a conversion from internal->internal is a no-op, any *existing* users of kind as a library should not see anything break if we make this switch (so long as type signatures stay the same)
- My biggest concern here is how we handle methods like 'ListNodesByRole', as these methods should really accept a versioned API type (imagine we renamed 'worker' to 'node' - how should this be converted?). Given this is an exported method, we'd probably need to add a conversion at the start of the exported method in order to make it possible for this to work with any API version.
- Circling back to how I started this (handling node roles?!??) - we need to consider how we handle conversion for const values/type aliases of strings. The conversion generator right now simply says `out.Role = NodeRole(in.Role)`. This is not really sufficient - we need this to be `out.Role = Convert_config_NodeRole_To_v1alpha3_NodeRole(in.Role)` in order to ensure we have a sane means to convert given we *could* rename node role values.
- As a completely separate thing, we *may* (in future, and this IMO is a separate issue) need to handle renaming label *keys* too. To do this we could probably move these label keys to be a part of our API and include conversions in our exported functions/methods between different key values too (similar to the label _values_). We'd then need to define one particular key that is stable between API versions that we can use to identify what API version the label keys used for a given config is. This might over-complicate our internal code a bit, but would give us flexibility to rename labels on docker contains in future too if needs be.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment