-
Notifications
You must be signed in to change notification settings - Fork 14
[OCPNODE-553] Migrate ICSP to ImageDigest,TagMirrorSet CRDs #15
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
[OCPNODE-553] Migrate ICSP to ImageDigest,TagMirrorSet CRDs #15
Conversation
mtrmac
left a comment
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.
Just an extremely brief skim for now, not really a review.
Let’s start with the ICSP discussion.
pkg/registries/registries.go
Outdated
| // mergedDigestMirrorSets processes idmsRules and returns a set of ImageDigestMirrors, one for each Source value, | ||
| // ordered consistently with the preference order of the individual entries (if possible) | ||
| // E.g. given mirror sets (B, C) and (A, B), it will combine them into a single (A, B, C) set. | ||
| func mergedDigestMirrorSets(idmsRules []*apicfgv1.ImageDigestMirrorSet) ([]apicfgv1.ImageDigestMirrors, error) { |
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.
At a first glance it seems to me that it should be possible to share more of the logic, but I haven’t read the code that carefully. (I do appreciate there’s a topoSortRepos now.)
Maybe an object that maintains disjointSets/mirrorBlockSource, with methods very vaguely like addMirrorSet(source, neverContactSource, mirrors) and mergedMirrorSets() []struct{source, neverContactSource, mirrors}? That way the two functions here would deal only with the data conversion with no logic at all.
Or maybe, instead of mergedMirrorSets, a sourceList() []string and updateRegistry(source, *Registry), to share more of the code in EditRegistriesConfig that just consumes the data from mergedMirrorSets.
e44218b to
1226049
Compare
|
@mtrmac PTAL. More code got shared. |
|
/retest |
Update go version from 1.16 to 1.17. openshift/runtime-utils#15 CI failed since the go is out of date, update the go version to fix it. Signed-off-by: Qi Wang <[email protected]>
|
/retest |
|
Issues go stale after 90d of inactivity. Mark the issue as fresh by commenting If this issue is safe to close now please do so with /lifecycle stale |
|
@QiWang19: PR needs rebase. DetailsInstructions 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. |
|
Stale issues rot after 30d of inactivity. Mark the issue as fresh by commenting If this issue is safe to close now please do so with /lifecycle rotten |
7017f07 to
268252f
Compare
|
@mtrmac could you review it? ICSP object migration should be done in MCO, this PR update uses new APIs. |
|
/remove-lifecycle rotten |
|
The pointer indirection is likely not needed. Can we refactor this by removing the pointer indirection such that the functions do not take a pointer, like:
and The mirrors attribute probably doesn't need to be a pointer. Likewise for the other functions in the file. |
Is that viable?
(It might well be fine. It’s just not what I vaguely remember the earlier migration conversations to be like, and I just thought I’d ask before we commit to that direction.) |
I’m sorry, actually reading the code, MCO is keeping the ICSP resources around, so they are still available to old consumers. That seems perfect to me. Back to actually reading this PR… |
2e6d143 to
bb15d8e
Compare
Upgrade to go 1.18, openshift/runtime-utils#15 failed the ci since go is out of date. Signed-off-by: Qi Wang <[email protected]>
bb15d8e to
b20a8ee
Compare
mtrmac
left a comment
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.
Two API semantics questions
And I’d like to push a bit further on the code sharing: The need to propagate blocked/insecure to sub-scopes is somewhat non-obvious, and having that triplicated feels a bit risky to me.
pkg/registries/registries.go
Outdated
| for _, mirror := range set.Mirrors { | ||
| if mirror != set.Source { | ||
| // rdmContainsARealMirror returns true if mirrors contains at least one entry that is not source. | ||
| func rdmContainsARealMirror(source string, mirrors []apicfgv1.ImageMirror) bool { |
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.
rdm refers to RepositoryDigestMirrors, so this should probably be renamed. mirrorsContainARealMirror? mirrorsContainSomeOtherThan?
pkg/registries/registries.go
Outdated
| } | ||
| } | ||
|
|
||
| // sourceList collects the mirror sources and sort them in increasing order |
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.
| // sourceList collects the mirror sources and sort them in increasing order | |
| // sourceList collects the mirror sources and returns them sorted in increasing order |
to be a bit clearer that this this does not affect the mirrorSets object.
pkg/registries/registries.go
Outdated
|
|
||
| func (sets *mirrorSets) addMirrorSets(source string, mirrorSourcePolicy apicfgv1.MirrorSourcePolicy, mirrors []apicfgv1.ImageMirror) { | ||
| if !rdmContainsARealMirror(source, mirrors) { | ||
| return // No mirrors (or mirrors that only repeat the authoritative source) is not really a mirror set. |
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.
Is it possible to have such a no-mirror object with NeverContactSource? If so, should we still set mirrorBlockSource?
(I’m most tempted to say that such an object is invalid and should be rejected, I’m not sure if it is practical. If it isn’t, both setting mirrorBlockSource and the current approach is, I guess, acceptable, but with the current approach, a extending the comment that yes, we ignore mirrorSourcePolicy and that’s intentional, would be useful.)
pkg/registries/registries.go
Outdated
| sources := tagMirrorSets.sourceList() | ||
| // Convert the sets of mirrors | ||
| res := []apicfgv1.ImageTagMirrors{} | ||
| for _, source := range sources { | ||
| source, mirrors, err := tagMirrorSets.mergedMirrors(source) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| imageTagMirror := apicfgv1.ImageTagMirrors{ | ||
| Source: source, | ||
| Mirrors: mirrors, | ||
| } | ||
| if tagMirrorSets.mirrorBlockSource[source] { | ||
| imageTagMirror.MirrorSourcePolicy = apicfgv1.NeverContactSource | ||
| } | ||
| res = append(res, imageTagMirror) | ||
| } | ||
| sort.Strings(sources) | ||
| return res, nil |
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 don’t think we need to return correctly-typed Image{Tag,Digest}Mirrors from the pair of these functions — so we could define a local type mergedMirrorsItem struct { source, mirrors, mirrorSourcePolicy } and all of this loop could be also shared.
pkg/registries/registries.go
Outdated
| return res, nil | ||
| } | ||
|
|
||
| func topoSortRepos(source string, ds *[][]apicfgv1.ImageMirror) ([]string, error) { |
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 is not just topological sort. Maybe {shared,raw}MergedMirrors? (Or, alternatively, if the loop calling this can be made shared, it can be inlined back. OTOH having this code as a separate function might be a better granularity for unit testing.)
pkg/registries/registries_test.go
Outdated
| set := apioperatorsv1alpha1.RepositoryDigestMirrors{ | ||
| Source: source, | ||
| Mirrors: tt.mirrors, | ||
| set := &apicfgv1.ImageTagMirrorSet{ |
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.
Non-blocking: If set is not used other than to read one of its fields, it doesn’t need to be constructed.
pkg/registries/registries_test.go
Outdated
| _, err := toml.Decode(string(templateBytes), &config) | ||
| require.NoError(t, err) | ||
| err = EditRegistriesConfig(&config, tt.insecure, tt.blocked, tt.icspRules, tt.idmsRules, tt.itmsRules) | ||
| require.NotNil(t, err) |
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.
Absolutely non-blocking: assert.NoError would be a better match here.
pkg/registries/registries_test.go
Outdated
| idmsRules []*apicfgv1.ImageDigestMirrorSet | ||
| itmsRules []*apicfgv1.ImageTagMirrorSet | ||
| icspRules []*apioperatorsv1alpha1.ImageContentSourcePolicy | ||
| want sysregistriesv2.V2RegistriesConf |
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.
insecure, blocked, want are unused, so that can be dropped.
Non-blocking: This test could be shorter and somewhat easier to fit on the screen with:
- Only including one set of mirrors instead of three in every item.
- Making the test data
idmsNonempty, itmsNonempty, icspNonempty bool, and letting the testing loop provide data or an empty array.
| Spec: apicfgv1.ImageTagMirrorSetSpec{ | ||
| ImageTagMirrors: []apicfgv1.ImageTagMirrors{ // other.com is neither insecure nor blocked | ||
| {Source: "insecure.com/ns-i1", Mirrors: []apicfgv1.ImageMirror{"blocked.com/ns-b1", "other.com/ns-o1"}}, | ||
| {Source: "blocked.com/ns-b/ns2-b", Mirrors: []apicfgv1.ImageMirror{"other.com/ns-o2", "insecure.com/ns-i2"}}, | ||
| {Source: "other.com/ns-o3", Mirrors: []apicfgv1.ImageMirror{"insecure.com/ns-i2", "blocked.com/ns-b/ns3-b", "foo.insecure-example.com/bar"}}, | ||
| }, |
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 test does not set anything to insecure nor blocked, so using the insecure.com/blocked.com domains is a bit unexpected.
What is being tested here? Just a smoke-test of correctly creating tag entries? Two entries would be enough for that.
|
The failing tests do seem to suggest that updating to Go ≥ 1.18 is required to be able to consume the new API module. |
Ah, that’s being handled in openshift/release#31916 . |
Upgrade to go 1.18, openshift/runtime-utils#15 failed the ci since go is out of date. Signed-off-by: Qi Wang <[email protected]> Signed-off-by: Qi Wang <[email protected]>
|
@mtrmac PTAL |
mtrmac
left a comment
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.
Thanks!
Implementation LGTM, just a few cleanup suggestions. Looking at the tests, I’m unsure why various tests were just dropped.
pkg/registries/registries.go
Outdated
|
|
||
| // Sort the sets of mirrors by Source to ensure deterministic output | ||
| // sourceList collects the mirror sources and returns them sorted in increasing order | ||
| func (sets *mirrorSets) sourceList() []string { |
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 now has only one caller and it can be inlined back.
pkg/registries/registries.go
Outdated
| return sources | ||
| } | ||
|
|
||
| func (sets *mirrorSets) addMirrorSets(source string, mirrorSourcePolicy apicfgv1.MirrorSourcePolicy, mirrors []apicfgv1.ImageMirror) { |
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.
| func (sets *mirrorSets) addMirrorSets(source string, mirrorSourcePolicy apicfgv1.MirrorSourcePolicy, mirrors []apicfgv1.ImageMirror) { | |
| func (sets *mirrorSets) addMirrorSet(source string, mirrorSourcePolicy apicfgv1.MirrorSourcePolicy, mirrors []apicfgv1.ImageMirror) { |
sets is multiple sets, this is adding a single one.
| strMirrors := []string{} | ||
| for _, m := range mirrors { | ||
| strMirrors = append(strMirrors, (string(m))) | ||
| } |
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.
Absolutely non-blocking: This copy is probably avoidable, perhaps with some more casts in the merging implementation.
(It’s a bit weird for ICSP to do a copy to convert to ImageMirror, only for this code to convert back to strings.)
But the cost is trivial either way, I’m not worried about it at all.
pkg/registries/registries.go
Outdated
| } | ||
|
|
||
| // mergedMirrors generates deterministic order of mirrors for a given source | ||
| func (sets *mirrorSets) mergedMirrors(source string) (string, []string, error) { |
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 doesn’t need to return source, it’s just the caller-supplied value.
pkg/registries/registries.go
Outdated
| return source, sortedRepos, nil | ||
| } | ||
|
|
||
| type mergedMirrorsItem struct { |
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.
Reading the full context, (contrary to my earlier suggestion — my mistake) mergedMirrorSet is probably the right name. That’s what it is (unlike “item”, which says nothing), and both functions like mergedICSPMirrorSets and variables like tagMirrorSets use that naming.
pkg/registries/registries_test.go
Outdated
| }) | ||
| } | ||
| tcRes := tc.result | ||
| if tc.name == "Separate mirror sets" { |
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 do this in the data.
pkg/registries/registries_test.go
Outdated
| if err != nil { | ||
| t.Errorf("Error %v", err) | ||
| return | ||
| } |
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.
Absolutely non-blocking: require.NoError(t, err) is shorter. This works just fine — and I realize the original was this way as well.
pkg/registries/registries_test.go
Outdated
| idmsRules: []*apicfgv1.ImageDigestMirrorSet{ | ||
| { | ||
| Spec: apicfgv1.ImageDigestMirrorSetSpec{ | ||
| ImageDigestMirrors: []apicfgv1.ImageDigestMirrors{ // other.com is neither insecure nor blocked |
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 comment seems inapplicable.
pkg/registries/registries_test.go
Outdated
| itmsRules: []*apicfgv1.ImageTagMirrorSet{ | ||
| { | ||
| Spec: apicfgv1.ImageTagMirrorSetSpec{ | ||
| ImageTagMirrors: []apicfgv1.ImageTagMirrors{ // other.com is neither insecure nor blocked |
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 comment seems inapplicable.
| {Source: "source.example.net", Mirrors: []string{"z1.example.net", "y2.example.net", "x3.example.net"}}, | ||
| }, | ||
| }, | ||
| { |
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.
The following test cases were dropped. Is there a specific reason for that? If not, please add them back.
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.
Added back. Accidently removed during the last code cleanup.
eca703f to
c29fe4c
Compare
|
@mtrmac PTAL. |
mtrmac
left a comment
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.
One very last thing - the tc.name == … condition.
LGTM otherwise.
pkg/registries/registries.go
Outdated
| } | ||
| sourceInGraph := false | ||
| for _, m := range mirrors { | ||
| if string(m) == source { |
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.
Non-blocking: The string() cast can now be dropped.
pkg/registries/registries.go
Outdated
| for i := range itms.Spec.ImageTagMirrors { | ||
| set := itms.Spec.ImageTagMirrors[i] |
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.
Absolutely non-blocking:
for _, set := range … { /* use set */ }would be one variable and one line shorter. (In all three instances.)
pkg/registries/registries.go
Outdated
| reg.Mirrors = updated | ||
| } | ||
| } | ||
|
|
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.
(Absolutely non-blocking: drop this line? I don’t think it separates “paragraphs” / individual ideas when placed here.)
pkg/registries/registries_test.go
Outdated
| func TestMergedICSPMirrorSets(t *testing.T) { | ||
| for _, tc := range mergedMirrorsetsTestcases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| if tc.name == "Separate mirror sets with mirrorSourcePolicy set" { |
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 make this driven by a real data field.
Either here,
if tc.requiresMirrorSourcePolicy { t.Skip() }(and set the tc.requiresMirrorSourcePolicy field on the test case), or (preferably?) make this fully automatic below, with something like
if item.mirrorSourcePolicy != "" {
t.Skip("…")
}
Add support for ImageDigestMirrorSet, ImageTagMirrorSet CRD Epic: https://issues.redhat.com/browse/OCPNODE-521 Epic: https://issues.redhat.com/browse/OCPNODE-810 Signed-off-by: Qi Wang <[email protected]>
Signed-off-by: Qi Wang <[email protected]>
c29fe4c to
f2400d4
Compare
|
@QiWang19: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions 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. I understand the commands that are listed here. |
|
/approve |
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: mtrmac, QiWang19 The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
Thanks! |
Migrate ICSP to ImageDigest,TagMirrorSet.
MCO has handled the object conversoin from icsp to ImageDiegstMirrorSet objects.
Epic: https://issues.redhat.com/browse/OCPNODE-521
Epic: https://issues.redhat.com/browse/OCPNODE-810
Signed-off-by: Qi Wang [email protected]