Skip to content
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

Parse remote cache attributes #3869

Merged
merged 17 commits into from Mar 12, 2024
Merged

Parse remote cache attributes #3869

merged 17 commits into from Mar 12, 2024

Conversation

hiddenmarten
Copy link
Contributor

Hi!

Addresses: #3868
A straightforward solution that works on my side.

I'm not sure that it's suitable to put these options next to the max mode, if not please lead me to the new flags in earthly that should be created.

@hiddenmarten hiddenmarten requested a review from a team as a code owner March 5, 2024 14:14
@CLAassistant
Copy link

CLAassistant commented Mar 5, 2024

CLA assistant check
All committers have signed the CLA.

@alexcb
Copy link
Collaborator

alexcb commented Mar 5, 2024

That's great to hear it unblocks your issue; however to accept this PR I think we would need to support parsing a config string that's formatted the same way that docker.

I had a look under buildkit and couldn't find any utility function for parsing these attributes -- maybe you could have better luck grepping for something?

Otherwise it feels easy enough for us to parse them via something like:

	func parseImageNameAndAttrs(s) (string, map[string]string, error) {
		entries := strings.Split(s, ",")
		imageName := entries[0]
		attrs := map[string][string]
		for _, entry := range entries[1:] {
			pair := strings.Split(strings.TrimSpace(entry), "=")
			//TODO check that len(pair) == 2
			attrs[k] = v
		}
	}
              

@@ -166,6 +166,8 @@ func newCacheExportOpt(ref string, max bool) client.CacheOptionsEntry {
registryCacheOptAttrs["ref"] = ref
if max {
registryCacheOptAttrs["mode"] = "max"
registryCacheOptAttrs["image-manifest"] = "true"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once we handle parsing the image string, I think it's better to assign the attr values outside of this if statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

@hiddenmarten
Copy link
Contributor Author

hiddenmarten commented Mar 7, 2024

I'm not quite sure about error handling, it should be better I suppose.
In general, the solution works for me.

@alexcb Thanks for the suggestion.

@hiddenmarten hiddenmarten requested a review from alexcb March 7, 2024 18:04
@alexcb
Copy link
Collaborator

alexcb commented Mar 7, 2024

I'm not quite sure about error handling, it should be better I suppose. In general, the solution works for me.

@alexcb Thanks for the suggestion.

good question!

how about parse them before calling the newCacheExportOpt function? something like:

$ git diff
diff --git a/builder/solver.go b/builder/solver.go
index be22709a..da7e74a6 100644
--- a/builder/solver.go
+++ b/builder/solver.go
@@ -98,10 +98,18 @@ func (s *solver) newSolveOptMulti(ctx context.Context, eg *errgroup.Group, onIma
        }
        var cacheExports []client.CacheOptionsEntry
        if s.cacheExport != "" {
-               cacheExports = append(cacheExports, newCacheExportOpt(s.cacheExport, false))
+               cacheExportName, attrs, err := parseImageNameAndAttrs(s.cacheExport)
+               if err != nil {
+                       return nil, errors.Wrapf(err, "parse cache export %s", s.cacheExport)
+               }
+               cacheExports = append(cacheExports, newCacheExportOpt(cacheExportName, attrs, false))
        }
        if s.maxCacheExport != "" {
-               cacheExports = append(cacheExports, newCacheExportOpt(s.maxCacheExport, true))
+               maxCacheExportName, attrs, err := parseImageNameAndAttrs(s.cacheExport)
+               if err != nil {
+                       return nil, errors.Wrapf(err, "parse max cache export %s", s.maxCacheExport)
+               }
+               cacheExports = append(cacheExports, newCacheExportOpt(maxCacheExportName, attrs, true))
        }
        if s.saveInlineCache {
                cacheExports = append(cacheExports, newInlineCacheOpt())

builder/solver.go Outdated Show resolved Hide resolved
builder/solver.go Outdated Show resolved Hide resolved
@hiddenmarten
Copy link
Contributor Author

Okay, it was a bit challenging for me :D

I wasn't able to implement all the modifications in builder/solver.go because it caused issues with the imports.

Consequently, I opted to relocate the parsing to build_cmd.go. I hope this won't cause any inconvenience.

@hiddenmarten hiddenmarten requested a review from alexcb March 9, 2024 17:49
This reverts commit 30f327766c975db25aaf8bf57f5562a41e8ce77f.
@hiddenmarten hiddenmarten changed the title Add image-manifest and oci-mediatypes opts next to max mode Parse explicit cache attributes Mar 9, 2024
@hiddenmarten hiddenmarten changed the title Parse explicit cache attributes Parse remote cache attributes Mar 9, 2024
if a.cli.Flags().RemoteCache != "" {
cacheImports = append(cacheImports, a.cli.Flags().RemoteCache)
cacheImportImageName, _, err = a.parseImageNameAndAttrs(a.cli.Flags().RemoteCache)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for discarding the attributes here? It would be better to raise an error saying attributes are not supported by

What about error handling?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I understand, in buildkit, there are only output keys and no input keys, which in Earthly terminology translates to export attributes without any corresponding import attributes. Consequently, these cannot be utilized in the import process without causing issues.

The critical aspect here is the --remote-cache flag, which facilitates the provision of a ref that applies to both exporting and importing. To address my concern, I should be able to specify attributes exclusively for the export process.

Additionally, I'm unclear about the import mechanism in Earthly. Specifically, I attempted to eliminate input attributes in the solver.go file, but this effort was unsuccessful. Earthly defaulted to using export attributes for the import process, which resulted in the malfunction of the import function.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I misunderstood this change earlier, I didn't appreciate the fact that the import is also set to the same RemoteCache value that's used for the export.

can you move the error handling to into this if statement -- currently the error handling is being run even when this code block is skipped.

In the case of imports, it might have been easier to just move parseImageNameAndAttrs into a utility package (and rename to ParseImageNameAndAttrs), which could be called both here and in the solver.go code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done.
@alexcb

if a.cli.Flags().RemoteCache != "" && a.cli.Flags().Push {
if a.cli.Flags().MaxRemoteCache {
maxCacheExport = a.cli.Flags().RemoteCache
maxCacheExport, cacheExportAttrs, err = a.parseImageNameAndAttrs(a.cli.Flags().RemoteCache)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the max cache setting ends up in a different variable name, I would create a similar one for attributes

Suggested change
maxCacheExport, cacheExportAttrs, err = a.parseImageNameAndAttrs(a.cli.Flags().RemoteCache)
maxCacheExport, maxCacheExportAttrs, err = a.parseImageNameAndAttrs(a.cli.Flags().RemoteCache)

(alternatively I would remove the MaxCacheExport field entirely, and just set the max attribute to true, but please don't do this in this PR, since it might be a larger task)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, the alternative option looks better.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just unsure if there's a chance the code was designed to support both a min and max export mode; that's why I'm wary of making an even bigger change in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you on this point.

P.S. Honestly, I think would be good to consider deprecating the --max-remote-cache flag and just adding a flag like: --export-cache-attributes, it looks a bit easier to understand from my point of view.

I can create an Issue on this topic if it is necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About your suggestion, it will lead to creating additional fields

	maxCacheExportAttrs map[string]string

in builder and solver structs, is that okay for you?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that is what I'm asking for, thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll do it now :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexcb done

}
}
if err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you do this immediately after each call

and please use a clearer error message, like the one I suggested earlier:

return nil, errors.Wrapf(err, "parse max cache export %s", s.maxCacheExport)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this hasn't been fully addressed -- can you do this immediately after each call

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added it in one more place

@hiddenmarten
Copy link
Contributor Author

I'll update the error handling soon.

@alexcb alexcb merged commit 30c9d54 into earthly:main Mar 12, 2024
2 checks passed
@alexcb
Copy link
Collaborator

alexcb commented Mar 12, 2024

Thanks for the help with this issue, and getting it across the finish line :)

@hiddenmarten
Copy link
Contributor Author

@alexcb
Thank you for the perfect lead :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved-for-tests Commnity PRs that the tests can run on
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

None yet

3 participants