Skip to content

Commit

Permalink
feat(source): support kubernetes
Browse files Browse the repository at this point in the history
  • Loading branch information
ekristen committed Oct 26, 2024
1 parent d1751e6 commit 91f2960
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 1 deletion.
32 changes: 31 additions & 1 deletion pkg/commands/install/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/ekristen/distillery/pkg/source"
)

func NewSource(src string, opts *provider.Options) (provider.ISource, error) {
func NewSource(src string, opts *provider.Options) (provider.ISource, error) { //nolint:funlen,gocyclo
detectedOS := osconfig.New(opts.OS, opts.Arch)

version := "latest"
Expand All @@ -36,6 +36,16 @@ func NewSource(src string, opts *provider.Options) (provider.ISource, error) {
Repo: parts[0],
Version: version,
}, nil
case source.KubernetesSource:
return &source.Kubernetes{
GitHub: source.GitHub{
Provider: provider.Provider{Options: opts, OSConfig: detectedOS},
Owner: source.KubernetesSource,
Repo: source.KubernetesSource,
Version: version,
},
AppName: parts[0],
}, nil
}

return nil, fmt.Errorf("invalid install source, expect format of owner/repo or owner/repo@version")
Expand All @@ -56,6 +66,16 @@ func NewSource(src string, opts *provider.Options) (provider.ISource, error) {
Repo: parts[1],
Version: version,
}, nil
} else if parts[0] == source.KubernetesSource {
return &source.Kubernetes{
GitHub: source.GitHub{
Provider: provider.Provider{Options: opts, OSConfig: detectedOS},
Owner: source.KubernetesSource,
Repo: source.KubernetesSource,
Version: version,
},
AppName: parts[1],
}, nil
}

switch opts.Config.DefaultSource {
Expand Down Expand Up @@ -85,6 +105,16 @@ func NewSource(src string, opts *provider.Options) (provider.ISource, error) {
Repo: parts[2],
Version: version,
}, nil
} else if parts[1] == source.KubernetesSource {
return &source.Kubernetes{
GitHub: source.GitHub{
Provider: provider.Provider{Options: opts, OSConfig: detectedOS},
Owner: source.KubernetesSource,
Repo: source.KubernetesSource,
Version: version,
},
AppName: parts[2],
}, nil
}

return &source.GitHub{
Expand Down
71 changes: 71 additions & 0 deletions pkg/source/kubernetes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package source

import (
"context"
"fmt"
"path/filepath"

"github.com/ekristen/distillery/pkg/asset"
)

const KubernetesSource = "kubernetes"

type Kubernetes struct {
GitHub

AppName string
}

func (s *Kubernetes) GetSource() string {
return KubernetesSource
}
func (s *Kubernetes) GetOwner() string {
return KubernetesSource
}
func (s *Kubernetes) GetRepo() string {
return s.Repo
}
func (s *Kubernetes) GetApp() string {
return fmt.Sprintf("%s/%s", s.Owner, s.Repo)
}
func (s *Kubernetes) GetID() string {
return fmt.Sprintf("%s-%s", s.GetSource(), s.GetRepo())
}

func (s *Kubernetes) GetDownloadsDir() string {
return filepath.Join(s.Options.Config.GetDownloadsPath(), s.GetSource(), s.GetOwner(), s.GetRepo(), s.Version)
}

func (s *Kubernetes) GetReleaseAssets(_ context.Context) error {
binName := fmt.Sprintf("%s-%s-%s-%s", s.AppName, s.Version, s.GetOS(), s.GetArch())
s.Assets = append(s.Assets, &KubernetesAsset{
Asset: asset.New(binName, s.AppName, s.GetOS(), s.GetArch(), s.Version),
Kubernetes: s,
URL: fmt.Sprintf("https://dl.k8s.io/release/v%s/bin/%s/%s/%s",
s.Version, s.GetOS(), s.GetArch(), s.AppName),
}, &KubernetesAsset{
Asset: asset.New(binName+".sha256", "", s.GetOS(), s.GetArch(), s.Version),
Kubernetes: s,
URL: fmt.Sprintf("https://dl.k8s.io/release/v%s/bin/%s/%s/%s.sha256",
s.Version, s.GetOS(), s.GetArch(), s.AppName),
})

return nil
}

func (s *Kubernetes) Run(ctx context.Context) error {
if err := s.sourceRun(ctx); err != nil {
return err
}

// this is from the Provider struct
if err := s.Discover([]string{s.Repo}); err != nil {
return err
}

if err := s.CommonRun(ctx); err != nil {
return err
}

return nil
}
112 changes: 112 additions & 0 deletions pkg/source/kubernetes_asset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package source

import (
"context"
"crypto/sha256"
"fmt"
"io"
"net/http"
"os"
"path/filepath"

"github.com/sirupsen/logrus"

"github.com/ekristen/distillery/pkg/asset"
"github.com/ekristen/distillery/pkg/common"
)

type KubernetesAsset struct {
*asset.Asset

Kubernetes *Kubernetes
URL string
}

func (a *KubernetesAsset) ID() string {
urlHash := sha256.Sum256([]byte(a.URL))
urlHashShort := fmt.Sprintf("%x", urlHash)[:9]

return fmt.Sprintf("%s-%s", a.GetType(), urlHashShort)
}

func (a *KubernetesAsset) Path() string {
return filepath.Join(KubernetesSource, a.Kubernetes.AppName, a.Kubernetes.Version)
}

func (a *KubernetesAsset) Download(ctx context.Context) error {
cacheDir, err := os.UserCacheDir()
if err != nil {
return err
}

downloadsDir := filepath.Join(cacheDir, common.NAME, "downloads")
filename := filepath.Base(a.URL)

assetFile := filepath.Join(downloadsDir, filename)
a.DownloadPath = assetFile
a.Extension = filepath.Ext(a.DownloadPath)

assetFileHash := assetFile + ".sha256"
stats, err := os.Stat(assetFileHash)
if err != nil && !os.IsNotExist(err) {
return err
}

if stats != nil {
logrus.Debug("file already downloaded")
return nil
}

logrus.Debugf("downloading asset: %s", a.URL)

req, err := http.NewRequestWithContext(context.TODO(), "GET", a.URL, http.NoBody)
if err != nil {
return err
}

req = req.WithContext(ctx)
req.Header.Add("User-Agent", fmt.Sprintf("%s/%s", common.NAME, common.AppVersion))

resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}

hasher := sha256.New()
tmpFile, err := os.Create(assetFile)
if err != nil {
return err
}
defer tmpFile.Close()

multiWriter := io.MultiWriter(tmpFile, hasher)

f, err := os.Create(assetFile)
if err != nil {
return err
}

// Write the asset's content to the temporary file
_, err = io.Copy(multiWriter, resp.Body)
if err != nil {
return err
}

if _, err := io.Copy(f, resp.Body); err != nil {
return err
}

logrus.Tracef("hash: %x", hasher.Sum(nil))

_ = os.WriteFile(assetFileHash, []byte(fmt.Sprintf("%x", hasher.Sum(nil))), 0600)
a.Hash = string(hasher.Sum(nil))

logrus.Tracef("Downloaded asset to: %s", tmpFile.Name())

return nil
}

0 comments on commit 91f2960

Please sign in to comment.