Restructure Microcluster packages#534
Conversation
Signed-off-by: Julian Pelizäus <julian.pelizaeus@canonical.com>
Signed-off-by: Julian Pelizäus <julian.pelizaeus@canonical.com>
I've not looked at the code, but if these structs need to be accessible to the caller why are they being moved to internal and then interfaces being used to solve the problem? |
One aspect is that we don't have to expose code which is not intended for public use. Another (most important in my opinion) is that you can mock the types for unit testing. Just updated the initial comment. |
Can you define the types externally to |
Yes that is the idea. This PR introduces a I'll rework both commits and PR description to be more concrete about what is happening but just wanted to push so that I have something to discuss with @markylaing in our next meet. |
There was a problem hiding this comment.
Pull Request Overview
This PR restructures Microcluster packages to improve API design by moving types from internal packages to public ones and introducing interfaces to enable better testing and mocking. The refactoring hides implementation details behind interfaces while making core types publicly accessible.
Key changes:
- Relocated types from
rest/,state/, and internal packages tomicrocluster/types/ - Introduced interfaces (
State,DB,OS,Client,Connector) to hide internal implementations - Converted client methods to standalone functions for better interface compliance
- Updated all import paths throughout the codebase
Reviewed Changes
Copilot reviewed 98 out of 103 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
microcluster/types/*.go |
New public type definitions moved from internal packages including State, DB, OS interfaces and core types |
rest/, state/ packages |
Deleted type alias files, functionality moved to microcluster/types |
internal/rest/client/client.go |
Client methods converted to standalone functions, added HTTP() accessor |
internal/state/state.go |
Updated to use new types package, added Connect() and Member() methods |
internal/db/ |
Updated schema and query imports to use public microcluster/db package |
internal/sys/os.go |
OS struct fields made private, added public accessor methods |
microcluster/app.go |
Updated to use new types and standalone client functions |
| Test files | Package names updated to reflect new structure (e.g., query_test → db_test) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
OK thanks for explaining. I would just say be cautious in using too many Interfaces and check they are truly needed because there is a cost to using them. I myself have used interfaces to break import cycles in the past so I understand what you are doing. |
Also ensure that all endpoints are covered by a client func in the app construct.
|
Few points from meeting:
|
So important! |
This is the first PR taken from a single commit in #534. The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. It consolidates the DB funcs and ensures the ones that should be used externally are public and not in the `internal` package. After the restructuring all the DB related functionality will be under the `microcluster/db` package alongside the app construct which is located in `microcluster`. See https://github.com/canonical/microcluster/pull/534/files
kadinsayani
left a comment
There was a problem hiding this comment.
The new package structure LGTM overall. Shall we also update the Makefile update-schema target in this PR?
❯ make update-schema
go generate ./cluster/...
pattern ./cluster/...: lstat ./cluster/: no such file or directory
make: *** [Makefile:66: update-schema] Error 1
Good catch. We should drop this overall as we agreed on not anymore using |
This is the second PR taken from a single commit in #534. The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. In this PR types which might end up on the user's end through the various channels (client funcs, app funcs, API handlers) are now moved to the central `microcluster/*` package which is the regular entry point for Microcluster users to derive an app construct.
This is the third PR taken from a single commit in #534. The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. In this PR the state directory utils (internal `sys` package) are not anymore returned directly from the state but are now hidden behind a common `OS` interface inside `microcluster/types` package. As the state is exposed to API handlers written by downstream users, this allows proper mocking. We should expose this to allow easy access to the daemon's config and certificates where necessary.
This is the fourth PR taken from a single commit in #534. The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. In this PR two new `Client` and `Connector` interfaces are added to address all use cases when it comes to cluster wide HTTP connections. In addition we now have app level funcs for all user facing operations which previously required going to a separate client package. Furthermore the specific query functions are now moved to `internal/` as they should not be exposed directly to the end user.
This is the fifth PR taken from a single commit in #534. The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. In this PR the opinionated `api.URL` type from LXD (which embeds the std libs `url.URL`) is replaced with the std libs `url.URL` to lower the amount of deps on LXD's `shared` package. But we still use it to allow fast crafting of URLs internally. Also it simplifies many statements that require access to an URL's `Host` as there is one less level of struct nesting.
This is the sixth PR taken from a single commit in #534 (even though in this case the actual changes are very different from the original commit). The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. In this PR the `Remotes` func from the `State` interface is replaced with an interface to not anymore return an implementation of the truststore with types located inside the `internal/` package. Furthermore the naming is made a bit more consistent: * `Store` represents a truststore * `Remote` represents an entry in the truststore The initial idea was to just hide the truststore access. However it's a very inexpensive way of querying for the existence and details of cluster members as the truststore is already located in memory.
This is the seventh PR taken from a single commit in #534 (even though in this case the actual changes are very different from the original commit). The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. In this PR the extensions package is made public so that the actual types can be accessed by importers of Microcluster.
Can only be merged after (won't build before): * #607 This is the eigth PR taken from a single commit in #534 (even though in this case the actual changes are very different from the original commit). The final package layout will be different but to allow reviewing the changes in smaller chunks I will split this PR by its commits. In this PR the DB interface is made public. It's returned by the public `State` interface and should therefore not be located inside the `internal/` package.
This started out small but after some changes I realized we have to properly hide structs behind interfaces to not anymore return datatypes which aren't usable by the user as they are placed inside the
internalpackage.With this PR I tried to remove all the pain points we have identified over the last years. Furthermore a user of Microcluster can now properly mock all the types to allow testing their DB and API handler logic.
More description and commit messages pending.