-
Notifications
You must be signed in to change notification settings - Fork 53
feat(ws): add ws counts to backend wsk model #368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: notebooks-v2
Are you sure you want to change the base?
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/ok-to-test |
b47474c
to
15e589e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I managed to (briefly) talk with Mathew during the WG call today (Thursday, May 29th) and he stated he was comfortable embedding this "counts" information more naturally inline with the response schema (and not worrying about adhering to a 1:1 structural mapping w.r.t how the information is presented from k8s)
The below image represents my proposal on how this "embedding" could work. A couple notes:
- The same schema should be applied to the "list" as well as the "get-by-id" endpoints
- For sake of brevity - I am only showing the "get-by-id" payload below
- I opted to "co-locate" the counts information closest to relevant data within the response. This is certainly most clean for the
values
arrays - but then leads to a rootworkspacesCount
attribute at the root of theWorkspaceKind
element as there isn't a more suitable place for it. - For sake of consistency/readability - I chose to re-use the same attribute name throughout (
workspacesCount
) - with the "pattern" being<child resource name (plural)>Count
... in the event this paradigm crops up elsewhere in the API - we could reuse this design philosophy - Certainly open to other's opinions on if this is the most appropriate design. I had considered a
counts: {....}
object as well... but chose not to advocate for that option as its too redundant/nested (having to repeat context likeimageConfig
as well as the IDs in order for a client to then have to perform the mapping to relevant object to display inline as we do in our table view today)

@andyatmiami: changing LGTM is restricted to collaborators In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Hey @andyatmiami |
@@ -153,3 +156,12 @@ func buildOptionRedirect(redirect *kubefloworgv1beta1.OptionRedirect) *OptionRed | |||
Message: message, | |||
} | |||
} | |||
|
|||
func FindConfigWorkspacesById(configs []kubefloworgv1beta1.OptionMetric, targetId string) int32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For optimal efficiency - I worry about this pattern of iterating through an array while we are already iterating over an array that gives us O(n^2)
We can improve this by iterating over the respective []kubefloworgv1beta1.OptionMetric
once each (for imageConfig and podConfig) and building up a map object that we can then pass into the build...ConfigValues
This ensures while we are iterating over the PodConfig/ImageConfig .Values
- we can get O(1) lookups for the respective counts.
Although being done in a slightly different context - you can see examples of "map initialization" in theNewWorkspaceKindModelFromWorkspaceKind
function:
So, feels like this new use case also "fits"...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @andyatmiami
That is a good point actually :) thanks for that!
Just fixed that please review when available
Thanks!
0e43df9
to
f8c3234
Compare
@thesuperzapper - PR ready / looking for your review/approval now - thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a chance to speak with @thesuperzapper about this PR - and here is the (hopefully!) last batch of feedback we have to give in order to get this PR merged 🤞
In the last round of edits - we made changes to expose a workspacesCount
attribute "inline" / co-located amongst the relevant JSON object.
We want to tweak this structure slightly.. instead of workspacesCount: <int>
- we want the following structure:
clusterMetrics: {
workspacesCount: <int>
}
This change will make more sense as I open up a couple other related issues based on recent discussions with Mathew - but the high level motivations are as such:
clusterMetrics
becomes a "bucket" to hold other future metrics in a well-understood structure- We will eventually add the concept of
namespaceMetrics
as well - to better delineate metrics that span the cluster (relevant to Joel) and metrics specific to a given namespace (relevant to Bella)- One of the driving forces behind this change is the "dual nature" of use cases the
GET /workspacekinds
API find itself in:- For Bella, when listing WorkspaceKinds as part of the Create Workspace flow, she may not have permissions/ability to view ALL workspaces... so if we only had a SINGLE count exposed, this could be confusing as she may not see the count aligned with the number of workspaces accessible to her
- For Joel, when listing WorkspaceKinds as part his workflow in the
Workspace Kinds
screen, he should have permissions/ability to view ALL workspaces... so presenting thisclusterMetrics
count is more natural / aligned with what he would find if clicking around in the UI
- One of the driving forces behind this change is the "dual nature" of use cases the
A few other implementation notes:
- while not possible to observe today, we would want
omitempty
defined on the struct forclusterMetrics
(however, as part of this PR,workspacesCount
will always be defined - Please add a
//TODO
somewhere relevant in the code to highlight the need to extend your solution to apply tonamespaceMetrics
(in the future, after I write that issue up and get it prioritized).. the need to calculatenamespaceMetrics
would be triggered via a request toGET /workspacekinds
having a?namespaceFilter
query parameter defined on it that would in some way be passed down intoNewWorkspaceKindModelFromWorkspaceKind
.. you don't need to implement these changes - just sharing for transparency/understanding)
ceec598
to
88d0e77
Compare
Labels []OptionLabel `json:"labels"` | ||
Hidden bool `json:"hidden"` | ||
Redirect *OptionRedirect `json:"redirect,omitempty"` | ||
ClusterMetrics clusterMetrics `json:"clusterMetrics"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ClusterMetrics clusterMetrics `json:"clusterMetrics"` | |
ClusterMetrics clusterMetrics `json:"clusterMetrics,omitempty"` |
Labels []OptionLabel `json:"labels"` | ||
Hidden bool `json:"hidden"` | ||
Redirect *OptionRedirect `json:"redirect,omitempty"` | ||
ClusterMetrics clusterMetrics `json:"clusterMetrics"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ClusterMetrics clusterMetrics `json:"clusterMetrics"` | |
ClusterMetrics clusterMetrics `json:"clusterMetrics,omitempty"` |
@@ -60,6 +62,10 @@ func NewWorkspaceKindModelFromWorkspaceKind(wsk *kubefloworgv1beta1.WorkspaceKin | |||
Hidden: ptr.Deref(wsk.Spec.Spawner.Hidden, false), | |||
Icon: iconRef, | |||
Logo: logoRef, | |||
// TODO: add namespaceMetrics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// TODO: add namespaceMetrics | |
// TODO: in the future will need to support including exactly one of clusterMetrics or namespaceMetrics based on request context |
func buildOptionMetricsMap(metrics []kubefloworgv1beta1.OptionMetric) map[string]int32 { | ||
resultMap := make(map[string]int32) | ||
for _, metric := range metrics { | ||
resultMap[metric.Id] = metric.Workspaces | ||
} | ||
return resultMap | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am legitimately torn here on a subtle and potentially in-this-context-unimportant implementation decision 😇
for _, metric := range metrics
will perform a copy on the elements defined in metrics
To avoid the copy - you can declare the for
loop as: for i := range metrics
However, I am then unsure how the body of the loop should be constructed
avoid copy (readable): metric := &metrics[i]
- as this is a pointer - if in the future someone modified this implementation for some reason to change this value - it would also change the actual element in the slice
avoid copy (less readable): resultMap[metrics[i].Id] = metrics[i].Workspaces
- less likely for someone in future to "accidentally" re-assign a value - but also not as visually pleasing to read
explicit copy: metric := metrics[i]
- intent more clear as compared to
for _, metric := range metrics
- as these structs are small - copy overhead not a concern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given these objects we are handling are inherently small (and bounded to be reasonably sure they will always be small) - the code here as written is sufficient.
…ma response Signed-off-by: rafriat <[email protected]>
/lgtm |
This PR solves issue #352