Skip to content

Generic provider#179

Open
speier wants to merge 6 commits into
marcosnils:masterfrom
speier:master
Open

Generic provider#179
speier wants to merge 6 commits into
marcosnils:masterfrom
speier:master

Conversation

@speier

@speier speier commented Nov 3, 2023

Copy link
Copy Markdown
Contributor

Started as a Helm provider, trying to turn into a generic provider, see comments below.

Provider to download Helm releases from https://get.helm.sh

Supports getting latest version from https://get.helm.sh/helm-latest-version or fetching specified version.

Unfortunately Helm using a rather strange way for their releases and they don't provide a list of release builds for OS/Arch, so we need to maintain a list of possible architecture and OS versions in the provider.

@marcosnils

Copy link
Copy Markdown
Owner

Hey! thx for the PR! retrieving binaries from direct http endpoints has been an idea that I've been waiting to generalize as a provider for a while and seems like this PR could be the perfect segway towards that. WDYT if we take this PR as a starting point and create a new http provider that additionally allows receiving a --lastest-url flag which basically takes care of this? I'd envision the UX something like

bin install --latest-url https://get.helm.sh/helm-latest-version https://get.helm.sh/helm-v3.13.1-linux-arm64.tar.gz

The idea is that bin will store the latest-url config and will use it for future bin update runs.

How does that sound?

@speier

speier commented Nov 5, 2023

Copy link
Copy Markdown
Contributor Author

Hi! Yes, sounds good. I was also wondering how to have a generic approach.

I will update the PR.

@speier speier changed the title Helm provider Generic provider Nov 5, 2023
@speier

speier commented Nov 7, 2023

Copy link
Copy Markdown
Contributor Author

Did you have a chance to take a look at the updated PR commits?

@MurzNN

MurzNN commented Dec 11, 2023

Copy link
Copy Markdown

It's a brilliant idea to provide providers with the most popular tools like helm, kubectl! Always get sad about downloading and updating them manually.

@marcosnils

Copy link
Copy Markdown
Owner

Did you have a chance to take a look at the updated PR commits?

hey! my apologies for delaying on this one. Will check it out this week 🙏

Comment thread cmd/install.go
all bool
force bool
provider string
latestURL string

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

we should move this latestURL inside the generic provider only since it doesn't apply to all of them

Comment thread cmd/install.go
// and triger the update process if that's the case

p, err := providers.New(u, root.opts.provider)
p, err := providers.New(u, root.opts.provider, root.opts.latestURL)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

same as the comment above. The provider itself should be the one who parses the latest url from the provided flags instead of sending this argument to all provider initializations. We'll have to refactor the code a bit but I believe it's worth it. We'll have to use different flagsets (https://pkg.go.dev/flag#NewFlagSet) per provider.

Comment thread cmd/install.go
Hash: fmt.Sprintf("%x", pResult.Hash.Sum(nil)),
URL: u,
Provider: p.GetID(),
LatestURL: root.opts.latestURL,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Same as other comments, having this in the top level of the config seems weird. I was thinking that we could maybe extend the provider key we already have and make it map instead of string. That way, we can save provider specific configurations in the config.

We could add a new GetConfig methgod to the provider interface for this.

Comment thread cmd/update.go

for _, b := range binsToProcess {
p, err := providers.New(b.URL, b.Provider)
p, err := providers.New(b.URL, b.Provider, b.LatestURL)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Same as comments in install.go

Comment thread cmd/update.go
for ui, b := range toUpdate {

p, err := providers.New(ui.url, b.Provider)
p, err := providers.New(ui.url, b.Provider, b.LatestURL)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Same as comments in install.go

Comment thread pkg/providers/generic.go

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

nit: renane generic.go to http_generic.go? WDYT?

Comment thread pkg/providers/generic.go
func (g *generic) GetLatestVersion() (string, string, error) {
log.Debugf("Getting latest release for %s", g.name)

resp, err := http.Get(g.latestURL)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

we should check if latestURL is not empty here so we can add proper debug logs for this with a message like: latest url not found for $name or something

)

func New(u, provider string) (Provider, error) {
func New(u, provider, latestURL string) (Provider, error) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Same as comments in install.go

return newHashiCorp(purl)
}

if len(latestURL) != 0 && (provider == "generic" || len(provider) == 0) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Same as comments in install.go

Comment thread pkg/providers/generic.go
return fname, fmt.Sprintf("%s/%s", g.baseURL, fname)
}

func newGeneric(u *url.URL, latestURL string) (Provider, error) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

seems like this provider is not very generic since it expects the URL to have a specific format or otherwise it'll fail. I'll leave a more general comment about this in the issue.

@marcosnils

Copy link
Copy Markdown
Owner

hey @speier just found the time to start looking at this and it's looking great and in the right direction. The most relevant comment I have is that the provider doesn't seem to be generic. If I understood the code correctly, if you give it an URL with a shape different than https://get.helm.sh/helm-v3.13.1-linux-arm64.tar.gz, it'll just fail to parse it and error out.

Maybe I didn't explain my idea very well before ( apologies, not a native English speaker). My initial thought was to allow the generic provider to be able to fetch any kind of URL regardless of the format. So I could also do something like bin install https://some_url/some_file.tar.gz and it'll also work. Optionally, this provider could receive a latest-url argument that it'll use to check if there's a new version (initially, it could only check if the value is different to what's persisted in the config) and download the new file if this is the case.

LMK if that makes sense or if there's something you see I'm missing.

Thx again for contributing!

@speier

speier commented Apr 19, 2024

Copy link
Copy Markdown
Contributor Author

hey @speier just found the time to start looking at this and it's looking great and in the right direction. The most relevant comment I have is that the provider doesn't seem to be generic. If I understood the code correctly, if you give it an URL with a shape different than https://get.helm.sh/helm-v3.13.1-linux-arm64.tar.gz, it'll just fail to parse it and error out.

Maybe I didn't explain my idea very well before ( apologies, not a native English speaker). My initial thought was to allow the generic provider to be able to fetch any kind of URL regardless of the format. So I could also do something like bin install https://some_url/some_file.tar.gz and it'll also work. Optionally, this provider could receive a latest-url argument that it'll use to check if there's a new version (initially, it could only check if the value is different to what's persisted in the config) and download the new file if this is the case.

LMK if that makes sense or if there's something you see I'm missing.

Thx again for contributing!

Hi! The idea was to use a somewhat standard naming convention: name-version-os-arch.ext otherwise not sure how it could work, if the url doesn't contain version/os/arch. Maybe I miss something here, but happy to discuss your ideas. Thx!

@needleshaped

Copy link
Copy Markdown

Hi! The idea was to use a somewhat standard naming convention: name-version-os-arch.ext otherwise not sure how it could work, if the url doesn't contain version/os/arch. Maybe I miss something here, but happy to discuss your ideas. Thx!

Hello! Please allow to join your discussion.

I would argue, that in case of generic provider such variables as os/arch should be at mercy of user. Otherwise we get non-generic provider. You could see another use case in #215, where the goal is to download shell scripts (like testssl).

As for version, "latestURL" variable name suggests, that we are handling "rolling" version.

Another discussible idea is how to optimize performance (save and check "Last-Modified" header, if exists?), or in worst case scenario - re-download and update (or better calculate hashsum and update only if necessary)

@marcosnils marcosnils dismissed a stale review January 30, 2025 00:01

bot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants