func HTTPDownload(dst string, src string) error {
	log.Infof("Start downloading from %s to %s ...\n", src, dst)
	var err error
	var out *os.File
	var resp *http.Response
	out, err = os.Create(dst)
	if err != nil {
		return err
	}
	defer func() {
		if err = out.Close(); err != nil {
			log.Errorf("Error: close file %s, %s", dst, err)
		}
	}()
	resp, err = http.Get(src)
	if err != nil {
		return err
	}
	defer func() {
		if err = resp.Body.Close(); err != nil {
			log.Errorf("Error: close downloaded file from %s, %s", src, err)
		}
	}()
	if resp.StatusCode != 200 {
		return fmt.Errorf("http get request, received unexpected response status: %s", resp.Status)
	}
	if _, err = io.Copy(out, resp.Body); err != nil {
		return err
	}
	log.Info("Download successfully!")
	return err
}
HTTPDownload download from src(url) and store into dst(local file)
package util
import (
	"archive/tar"
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"
	"github.com/google/go-github/github"
	"github.com/pkg/errors"
	"istio.io/istio/pkg/test/env"
	"istio.io/pkg/log"
)
const (
	releaseURL = "https://github.com/istio/istio/releases/download/%s/istio-%s-%s.tar.gz"
)
func GetHeadCommitSHA(org, repo, branch string) (string, error) {
	client := github.NewClient(nil)
	githubRefObj, _, err := client.Git.GetRef(
		context.Background(), org, repo, "refs/heads/"+branch)
	if err != nil {
		log.Warnf("Failed to get reference SHA of branch [%s]on repo [%s]\n", branch, repo)
		return "", err
	}
	return *githubRefObj.Object.SHA, nil
}
func WriteTextFile(filePath, content string) error {
	if len(content) > 0 && content[len(content)-1] != '\n' {
		content += "\n"
	}
	return ioutil.WriteFile(filePath, []byte(content), 0600)
}
func GitRootDir() (string, error) {
	dir, err := Shell("git rev-parse --show-toplevel")
	if err != nil {
		return "", err
	}
	return strings.Trim(dir, "\n"), nil
}
func Poll(interval time.Duration, numTrials int, do func() (bool, error)) error {
	if numTrials < 0 {
		return fmt.Errorf("numTrials cannot be negative")
	}
	for i := 0; i < numTrials; i++ {
		if success, err := do(); err != nil {
			return fmt.Errorf("error during trial %d: %v", i, err)
		} else if success {
			return nil
		} else {
			time.Sleep(interval)
		}
	}
	return fmt.Errorf("max polling iteration reached")
}
func CreateTempfile(tmpDir, prefix, suffix string) (string, error) {
	f, err := ioutil.TempFile(tmpDir, prefix)
	if err != nil {
		return "", err
	}
	var tmpName string
	if tmpName, err = filepath.Abs(f.Name()); err != nil {
		return "", err
	}
	if err = f.Close(); err != nil {
		return "", err
	}
	if err = os.Remove(tmpName); err != nil {
		log.Errorf("CreateTempfile unable to remove %s", tmpName)
		return "", err
	}
	return tmpName + suffix, nil
}
func WriteTempfile(tmpDir, prefix, suffix, contents string) (string, error) {
	fname, err := CreateTempfile(tmpDir, prefix, suffix)
	if err != nil {
		return "", err
	}
	if err := ioutil.WriteFile(fname, []byte(contents), 0644); err != nil {
		return "", err
	}
	return fname, nil
}
func Shell(format string, args ...interface{}) (string, error) {
	return sh(context.Background(), format, true, true, true, args...)
}
func ShellContext(ctx context.Context, format string, args ...interface{}) (string, error) {
	return sh(ctx, format, true, true, true, args...)
}
func ShellMuteOutput(format string, args ...interface{}) (string, error) {
	return sh(context.Background(), format, true, false, true, args...)
}
func ShellMuteOutputError(format string, args ...interface{}) (string, error) {
	return sh(context.Background(), format, true, false, false, args...)
}
func ShellSilent(format string, args ...interface{}) (string, error) {
	return sh(context.Background(), format, false, false, false, args...)
}
func sh(ctx context.Context, format string, logCommand, logOutput, logError bool, args ...interface{}) (string, error) {
	command := fmt.Sprintf(format, args...)
	if logCommand {
		log.Infof("Running command %s", command)
	}
	c := exec.CommandContext(ctx, "sh", "-c", command)  
	bytes, err := c.CombinedOutput()
	if logOutput {
		if output := strings.TrimSuffix(string(bytes), "\n"); len(output) > 0 {
			log.Infof("Command output: \n%s", output)
		}
	}
	if err != nil {
		if logError {
			log.Infof("Command error: %v", err)
		}
		return string(bytes), fmt.Errorf("command failed: %q %v", string(bytes), err)
	}
	return string(bytes), nil
}
func RunBackground(format string, args ...interface{}) (*os.Process, error) {
	command := fmt.Sprintf(format, args...)
	log.Infoa("RunBackground: ", command)
	parts := strings.Split(command, " ")
	c := exec.Command(parts[0], parts[1:]...)  
	err := c.Start()
	if err != nil {
		log.Errorf("%s, command failed!", command)
		return nil, err
	}
	return c.Process, nil
}
func Record(command, record string) error {
	resp, err := Shell(command)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(record, []byte(resp), 0600)
	return err
}
func GetOsExt() (string, error) {
	var osExt string
	switch runtime.GOOS {
	case "linux":
		osExt = "linux"
	case "darwin":
		osExt = "osx"
	default:
		return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
	}
	return osExt, nil
}
func CopyFile(src, dst string) error {
	var in, out *os.File
	var err error
	in, err = os.Open(src)
	if err != nil {
		return err
	}
	defer func() {
		if err = in.Close(); err != nil {
			log.Errorf("Error: close file from %s, %s", src, err)
		}
	}()
	out, err = os.Create(dst)
	if err != nil {
		return err
	}
	defer func() {
		if err = out.Close(); err != nil {
			log.Errorf("Error: close file from %s, %s", dst, err)
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return err
	}
	err = out.Sync()
	return err
}
func GetResourcePath(p string) string {
	return filepath.Join(env.IstioSrc, p)
}
func DownloadRelease(version, tmpDir string) (string, error) {
	err := os.Chdir(tmpDir)
	if err != nil {
		return "", err
	}
	osExt, err := GetOsExt()
	if err != nil {
		return "", err
	}
	url := fmt.Sprintf(releaseURL, version, version, osExt)
	fname := fmt.Sprintf("istio-%s.tar.gz", version)
	tgz := filepath.Join(tmpDir, fname)
	err = HTTPDownload(tgz, url)
	if err != nil {
		return "", err
	}
	f, err := os.Open(tgz)
	if err != nil {
		return "", err
	}
	err = ExtractTarGz(f, tmpDir)
	if err != nil {
		return "", err
	}
	subdir := "istio-" + version
	return filepath.Join(tmpDir, subdir), nil
}
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func RandomString(n int) string {
	rand.Seed(time.Now().UnixNano())
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Int63()%int64(len(letters))]
	}
	return string(b)
}