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

[WIP] Support for @v/list and @latest endpoints in an offline environment #1676

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

kralicky
Copy link

@kralicky kralicky commented Nov 14, 2020

What is the problem I am trying to address?

I am using Athens to use go modules in an offline, air-gapped environment. With download mode set to none, the @v/list and @latest api endpoints are still trying to go out to the internet to retrieve version information.

How is the fix applied?

When download mode is set to none and disk storage is used, @v/list will list only the modules available on disk, and @latest will return the latest version from the modules available on disk. It will not try to go out to the internet, since nothing can be downloaded anyway with download mode set to none.

So far these changes are working perfectly in my environment. I am able to develop using go modules as if I was online with no workflow changes or workarounds.

TODO: the implementation of @latest (sorting all the versions) could probably be moved somewhere else and/or simplified.

For reference, I am using the following system to synchronize the disk storage between my online and offline networks:

  • On the online machine, keep an empty go project with a go.mod listing all the direct dependencies you need
  • Run this command to download all dependencies recursively into the local module download cache (~/go/pkg/mod/cache/download).
    • This is important, and a simple go mod download doesn't really work, because (as far as I can tell) outdated semver-compatible dependencies need to be found before the go module system can decide that they can be updated. For example: your package directly requires foo v1.0.2. A dependency of yours requires foo v1.0.1. When online, go finds v1.0.1, but also knows that v1.0.2 is available, and the dependency's foo is updated to v1.0.2 automatically since it's semver compatible. But when offline, go still needs to be able to locate v1.0.1, which means we need both versions in our Athens disk cache. go mod download will only give you v1.0.2.
  • Copy the download cache to the offline machine
  • Rename the files/folders into the format that Athens wants, copy everything into the Athens disk cache, and restart it.

This works and it's relatively easy. It would be nice to be able to configure Athens to serve the default download cache disk format instead of needing to re-structure the files. Maybe that could be a potential improvement for this PR.

Reference issue

Closes #1868

@kralicky kralicky requested a review from a team as a code owner November 14, 2020 22:10
@arschles
Copy link
Member

arschles commented Nov 19, 2020

@cobalt77 I wanted to let you know that we're not ignoring this, I just need to take my time reviewing it. this feature has a relatively long history of discussion and I need to research all the relevant past PRs and issues so I can properly comment on it. I'll do that and come back to it early next week.

Copy link
Member

@arschles arschles left a comment

Choose a reason for hiding this comment

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

@cobalt77 except for my comment about mode.None, I think this is a good step toward enabling an "offline" mode that @nathanhack and others talked about in this thread

@@ -74,19 +77,27 @@ func (p *protocol) List(ctx context.Context, mod string) ([]string, error) {
ctx, span := observ.StartSpan(ctx, op.String())
defer span.End()

// If the download mode is None, we won't be downloading anything from
// the internet anyway, so we should only examine local storage.
localOnly := p.df.Match(mod) == mode.None
Copy link
Member

Choose a reason for hiding this comment

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

@cobalt77 I think we need a different signal to determine when to not look to the internet. mode.None means that a 404 should be returned for this module, unless I'm misunderstanding something?

Copy link
Author

Choose a reason for hiding this comment

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

Thought a lot about this. Let's say I have the following setup:

  • Offline environment, and a self-hosted git server with some go modules
  • Athens with file based storage and a dynamic config where all modules except my.git.server.com/* get download mode "None"

If I go get github.com/something, that will use download mode None and treat the contents of the athens cache as ground truth, and get me the latest of the available modules.
If I go get my.git.server.com/somethingelse, athens will go out to my git server for the module, and not assume that what's in cache is the latest.

This will work as expected with this change. But it changes what None does, and maybe there is a scenario where a 404 would be preferable. Or in online environments, athens treating the cache as ground truth sometimes but not all the time could lead to nondeterministic behavior or other weird issues.

What do you think about keeping None as-is (always 404 if it doesn't exist), and adding a new separate download mode that will do this?

if err != nil {
return nil, errors.E(op, err)

localOnly := p.df.Match(mod) == mode.None
Copy link
Member

Choose a reason for hiding this comment

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

same as my comment above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Clarify expected behavior of /@latest endpoint in fallback NetworkMode
3 participants