kubenetworks/kubevpn

View on GitHub
pkg/upgrade/upgrade.go

Summary

Maintainability
A
3 hrs
Test Coverage
package upgrade

import (
    "context"
    "fmt"
    "net/http"
    "os"
    "path/filepath"
    "runtime"
    "strings"

    goversion "github.com/hashicorp/go-version"
    log "github.com/sirupsen/logrus"

    "github.com/wencaiwulue/kubevpn/v2/pkg/daemon"
    "github.com/wencaiwulue/kubevpn/v2/pkg/daemon/elevate"
    "github.com/wencaiwulue/kubevpn/v2/pkg/util"
)

// Main
// 1) get current binary version
// 2) get the latest version
// 3) compare two version decide needs to download or not
// 4) download newer version zip
// 5) unzip to temp file
// 6) check permission of putting new kubevpn back
// 7) chmod +x, move old to /temp, move new to CURRENT_FOLDER
func Main(ctx context.Context, client *http.Client, url string) error {
    err := elevatePermission()
    if err != nil {
        return err
    }

    err = downloadAndInstall(client, url)
    if err != nil {
        return err
    }

    log.Infof("Upgrade daemon...")
    err = daemon.StartupDaemon(context.Background())
    log.Info("Done")
    return err
}

func downloadAndInstall(client *http.Client, url string) error {
    temp, err := os.CreateTemp("", "*.zip")
    if err != nil {
        return err
    }
    defer os.Remove(temp.Name())
    err = temp.Close()
    if err != nil {
        return err
    }
    err = util.Download(client, url, temp.Name(), os.Stdout, os.Stderr)
    if err != nil {
        return err
    }

    var curFolder string
    curFolder, err = os.Executable()
    if err != nil {
        return err
    }
    var file *os.File
    file, err = os.CreateTemp(filepath.Dir(curFolder), "")
    if err != nil {
        return err
    }
    defer os.Remove(file.Name())
    err = file.Close()
    if err != nil {
        return err
    }
    err = util.UnzipKubeVPNIntoFile(temp.Name(), file.Name())
    if err != nil {
        return err
    }
    err = os.Chmod(file.Name(), 0755)
    if err != nil {
        return err
    }

    var createTemp *os.File
    createTemp, err = os.CreateTemp(filepath.Dir(curFolder), "")
    if err != nil {
        return err
    }
    defer os.Remove(createTemp.Name())
    err = createTemp.Close()
    if err != nil {
        return err
    }
    err = os.Remove(createTemp.Name())
    if err != nil {
        return err
    }
    err = util.Move(curFolder, createTemp.Name())
    if err != nil {
        return err
    }
    err = util.Move(file.Name(), curFolder)
    return err
}

func elevatePermission() error {
    executable, err := os.Executable()
    if err != nil {
        return err
    }
    var tem *os.File
    tem, err = os.Create(filepath.Join(filepath.Dir(executable), ".test"))
    if tem != nil {
        _ = tem.Close()
        _ = os.Remove(tem.Name())
    }
    if err == nil {
        return nil
    }
    if os.IsPermission(err) {
        elevate.RunWithElevated()
        os.Exit(0)
    } else if err != nil {
        return err
    } else if !elevate.IsAdmin() {
        elevate.RunWithElevated()
        os.Exit(0)
    }
    return nil
}

func NeedsUpgrade(ctx context.Context, client *http.Client, version string) (url string, latestVersion string, upgrade bool, err error) {
    latestVersion, url, err = util.GetManifest(client, runtime.GOOS, runtime.GOARCH)
    if err != nil {
        v := "https://github.com/kubenetworks/kubevpn/raw/master/plugins/stable.txt"
        var stream []byte
        stream, err = util.DownloadFileStream(v)
        latestVersion = strings.TrimSpace(string(stream))
        url = fmt.Sprintf("https://github.com/kubenetworks/kubevpn/releases/download/%s/kubevpn_%s_%s_%s.zip", latestVersion, latestVersion, runtime.GOOS, runtime.GOARCH)
    }
    if err != nil {
        return
    }

    var currV, latestV *goversion.Version
    currV, err = goversion.NewVersion(version)
    if err != nil {
        return
    }
    latestV, err = goversion.NewVersion(latestVersion)
    if err != nil {
        return
    }
    if currV.GreaterThanOrEqual(latestV) {
        return
    }
    upgrade = true
    return
}