-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Store the container-machine mapping predictably #13858
Store the container-machine mapping predictably #13858
Conversation
predictable name length to prevent breaking the 63 character limit on the k8s annotation names. Signed-off-by: Lukas Krejci <lkrejci@redhat.com>
What makes the machine name size predictable? To me it looks like it's still a function of the name of the container. |
It's not the machine name that has a predictable size - as you correctly note, it is a function of the container name. Before, we stored the mapping from the container name to the machine name using a single annotation that included the container name in its key. E.g.:
As you see above, the length of the annotation key is unpredictable and depends on the name of the container. This PR changes the mapping into 2 annotations:
And contains additional logic to increment the "1" in the above names for additional mappings if the pod contains more containers. The length of the annotation keys is thus predictable and it is hard to imagine it going past the 63 character limit because that would require there to be more than 10^43 containers in a single pod. Also the PR changes the code in all the places that used to read the machine name from the annotations directly to delegate that to the methods in |
Signed-off-by: Lukas Krejci <lkrejci@redhat.com>
ci-test |
Results of automated E2E tests of Eclipse Che Multiuser on OCP: |
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'm personally not a huge fan of this approach -- it adds a fair bit of complexity and looks like a hack at the end of the day.
If the machine name annotation is never used, then why don't we remove it? It makes more sense to add the logic for how this annotating is done once something actually needs to use it.
Alternatively, changing MACHINE_NAME_ANNOTATION_FORMAT
to org.eclipse.che.machine-name/%s
would solve the problem for any container with a name less than 63 characters since everything before /
is a prefix.
Added a few optional suggestions.
@davidfestal Just to double check but does this affect your operator work?
return null; | ||
} | ||
|
||
for (Map.Entry<String, String> e : annotations.entrySet()) { |
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.
This could likely be made a lot simpler and more readable in a stream:
annotations.entrySet()
.stream()
.filter(e -> e.getKey().startsWith(CONTAINER_META_PREFIX))
.filter(e -> e.getKey().endsWith(CONTAINER_META_NAME_SUFFIX))
.filter(e -> containerName.equals(e.getValue()))
.map(...)
.collect(...)
|
||
String index = | ||
key.substring( | ||
CONTAINER_META_PREFIX.length(), key.length() - CONTAINER_META_NAME_SUFFIX.length()); |
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.
A cleaner way to do this would be to match it out using a regex based off of prefix and suffix.
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.
Call me old school, but I fail to see how is that cleaner... If you insist, I can change it, but substring is IMHO both faster and functionally simpler than regex matching.
|
||
private static final String CONTAINER_META_PREFIX = "che.container."; | ||
private static final String CONTAINER_META_NAME_SUFFIX = ".name"; | ||
private static final String CONTAINER_META_MACHINE_SUFFIX = ".machine"; |
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.
To me it looks better if you use
CONTAINER_META_NAME = "che.container.%s.name";
CONTAINER_META_MACHINE = "che.contianer.%s.machine";
an then String.format()
the indexes in.
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.
According to the casual Google search, format
is at least an order of magnitude slower than concatenation. I would 100% agree with you if these were localizable strings, but they're not.
return max; | ||
} | ||
|
||
for (String key : annotations.keySet()) { |
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.
Could also be a stream operation, something like:
annotations.keySet()
.stream()
.mapToInt()
.max()
I also don't like the numbering very much. That means that you have to know the final number of containers at start, before generating the deployment annotations but obviously after doing brokering. In the Workspace CRD controller POC that's not the case for example. We add containers in the overall workspace deployment PodSpec as soon as a plugin component is found in the devfile and brokering is called on-the-fly in the controller itself for this component. I really like better the alternate approach @amisevsk proposed:
|
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.
Have you investigated the possibility of getting rid of a machine name in annotations?
Generally, I'm OK with the proposed solution since it solves an issue and looks like we would be able to get rid of this quite complex logic along with WorkspaceConfig format (maybe current Runtime model)
Comment about org.eclipse.che.machine-name/%s
:
org.eclipse.che.machine-name/
has 29 characters and it would mean that we should limit machine name to 34
characters and everything that propagated as machine name, like alias of dockerimage component, also we should introduce algorithm of how we transform image
of dockerimage component to machine name (now it does not have limit of characters). Machine name concept is a core concept and no one knows every place that is affected by this. I think it can be investigated more, and it's not equivalent to the current approach that allows using unlimited (quite long) machine name.
if (annotations != null | ||
&& (machineName = annotations.get(format(MACHINE_NAME_ANNOTATION_FMT, containerName))) | ||
!= null) { | ||
if ((machineName = findMachineName(annotations, containerName)) != null) { |
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.
Please consider updating of java docs as well.
I don't see any java docs that would explain how we store machines names in annotations. I guess, previously java doc of MACHINE_NAME_ANNOTATION_FMT
const has some short info.
@@ -98,4 +162,83 @@ public static String uniqueResourceName(String originalResourceName, String work | |||
public static String generateName(String prefix) { | |||
return NameGenerator.generate(prefix, GENERATED_PART_SIZE); | |||
} | |||
|
|||
private static String findMachineName(Map<String, String> annotations, String containerName) { |
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.
Please add @nullable
for (Map.Entry<String, String> e : annotations.entrySet()) { | ||
String key = e.getKey(); | ||
|
||
if (!key.startsWith(CONTAINER_META_PREFIX)) { |
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 see quite the same logic in findContainerIndex
method, maybe we can rewrite this method in the following way to reduce the same code:
@Nullable
private static String findMachineName(Map<String, String> annotations, String containerName) {
int index = findContainerIndex(annotations, containerName);
if (index < 0) {
return null;
}
String machineNameKey = CONTAINER_META_PREFIX + index + CONTAINER_META_MACHINE_SUFFIX;
return annotations.get(machineNameKey);
}
} | ||
|
||
for (String key : annotations.keySet()) { | ||
if (!(key.startsWith(CONTAINER_META_PREFIX) && key.endsWith(CONTAINER_META_NAME_SUFFIX))) { |
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.
What do you think about using Pattern instead of startsWith+endsWith+substring?
Like the following
https://gist.github.com/sleshchenko/f2190306fdd7c9dc2cbb071bc22d64e0
tldr; Yes, it is a hack put in place to fix the current wrong behavior with minimal impact on the codebase. The hopes are the need for the mapping goes away once we change the k8s infra internals that are still implemented around the old domain model.
The I looked at them while investigating this and, mostly, the mapping is used to map the old model of servers/installers/machines that we still use internally to the actual k8s deployment. As such, I decided to not try to get rid of this mapping because it would be too risky at this point in time.
while this would improve the situation greatly, it still imposes a limit that we don't enforce anywhere. So I chose an approach that doesn't impose that limit again to keep the impact of the change to the minimum. If I merely switched to the format you suggest, I'd have to also modify all the places that result in definition of a machine name (devfile appliers, factory, workspace config, ...) and add the length validation. That said, if we agree here that such validation wouldn't be needed (to limit the scope of the change), I am more than happy to apply that format. I like it better, too.
I believe that's not the case. At least in the current implementation, no outside caller knows anything about any numbering. The numbering is a mere implementation choice of the |
@metlos I'm speaking with the Workspace CRD Operator POC in mind: it creates the various Che workspace K8S resources without using the internal k8s infrastructure implementation. It uses its own logic implementation to provide compatible K8S resources. And in this context, using this type of numbering seems more a backward step than a forward one, and makes it more complicated. That said, I just wanted to notify you, but that's not a blocker, I'll accommodate. |
Ok, I see what you mean now. You want to keep compatibility between workspaces created using the CRD and che server. I didn't take that into account actually. Not sure we need to be backwards compatible here, though. I assume you don't need these annotations in your implementation at all? |
For various reason, I think we should keep compatibility between both, at least for a certain amount of time. But as I said, I'll accommodate on the Workspace CRD side if you don't have any better solution for now on your side. |
Signed-off-by: Lukas Krejci <lkrejci@redhat.com>
@sleshchenko For annotations, a up-to-256-char prefix is permitted (the I agree on it still imposing a limit we don't enforce, however. |
…ions-too-long Signed-off-by: Lukas Krejci <lkrejci@redhat.com>
Signed-off-by: Lukas Krejci <lkrejci@redhat.com>
Signed-off-by: Lukas Krejci <lkrejci@redhat.com>
I reviewed all the involved code again and I think we can reasonably assume that the container can always be < 63 chars. The plugins/editors already have that limitation in place (or rather they just trim the name to be < 63 chars) and for dockerimages I added a validation check that will fail the deployment of a devfile and will suggest to adding an alias for such component. The kubernetes/openshift components don't seem to be involved in machine naming at all (or at least they don't manifest themselves in the workspace pod annotations). Thanks for the suggestion @amisevsk! |
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.
LGTM, thanks @metlos !
@@ -257,6 +257,14 @@ static String toMachineName(String imageName) throws DevfileException { | |||
return imageName; | |||
} | |||
|
|||
if (imageName.length() > Names.MAX_CONTAINER_NAME_LENGTH) { |
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.
Isn't it something that can be checked by JSON Schema?
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.
Well, we can't really restrict the names of the images. What would have to happen is conditional check that would mark alias required if the length of the image name would be > 63. Maybe it is doable in the schema but we have to have the check in the code anyway. So for simplicity's sake I only did it in the code. I believe the PR is writable by contributors so please add the schema changes if required (I don't have access to my computer this week).
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.
LGTM
ci-test |
Results of automated E2E tests of Eclipse Che Multiuser on OCP: |
ci-test |
Results of automated E2E tests of Eclipse Che Multiuser on OCP: |
I've retest locally the same stack (go) that failed for |
ci-test |
Results of automated E2E tests of Eclipse Che Multiuser on OCP: |
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.
+0. Others have already +1'd and I'm clearing my PR review backlog. No opinion as I'm not SME here.
Signed-off-by: Sergii Leshchenko <sleshche@redhat.com>
ci-test |
Results of automated E2E tests of Eclipse Che Multiuser on OCP: |
Selenium tests execution on Eclipse Che Multiuser on OCP (https://ci.codenvycorp.com/job/che-pullrequests-test-ocp/1941/) doesn't show any regression against this Pull Request. |
What does this PR do?
Store the container-machine mapping using a pair of annotations with a
predictable name length to prevent breaking the 63 character limit on the
k8s annotation names.
What issues does this PR fix or reference?
#13303