github.com/ETCDEVTeam/janus@v0.2.4-0.20180611132348-f6c8fba730fa/gcp/gcp.go (about) 1 package gcp 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "strconv" 14 "strings" 15 16 "cloud.google.com/go/storage" 17 "google.golang.org/api/option" 18 ) 19 20 var decryptedKeyFileName = "./" + strconv.Itoa(os.Getpid()) + "-gcloud.json" 21 22 // Use: go run gcs-deploy.go -bucket builds.etcdevteam.com -object go-ethereum/$(cat version-base.txt)/geth-classic-$TRAVIS_OS_NAME-$(cat version-app.txt).zip -file geth-classic-linux-14.0.zip -key ./.gcloud.key 23 24 // writeToGCP writes (uploads) a file or files to GCP Storage. 25 // 'object' is the path at which 'file' will be written, 26 // 'bucket' is the parent directory in which the object will be written. 27 func writeToGCP(client *storage.Client, bucket, object, file string) error { 28 29 ctx := context.Background() 30 // [START upload_file] 31 f, err := os.Open(file) 32 if err != nil { 33 return err 34 } 35 defer f.Close() 36 37 // Write object to storage, ensuring basename for file/object if exists. 38 wc := client.Bucket(bucket).Object(object).NewWriter(ctx) 39 if _, err = io.Copy(wc, f); err != nil { 40 return err 41 } 42 if err := wc.Close(); err != nil { 43 return err 44 } 45 // [END upload_file] 46 fmt.Printf(`Successfully uploaded: 47 bucket: %v 48 object: %v 49 file: %v 50 `, bucket, object, file) 51 return nil 52 } 53 54 // SendToGCP sends a file or files to Google Cloud Provider storage 55 // using a service account JSON key 56 func SendToGCP(to, files, key string, gpg bool) error { 57 58 to = filepath.Clean(to) 59 files = filepath.Clean(files) 60 key = filepath.Clean(key) 61 62 // Ensure key file exists. 63 if _, e := os.Stat(key); e != nil { 64 return e 65 } 66 67 var arbitraryMap = make(map[string]interface{}) 68 69 // Read key file 70 bRead, eRead := ioutil.ReadFile(key) 71 if eRead != nil { 72 return eRead 73 } 74 75 // Attempt to unmarshal key file, checks for encryption 76 e := json.Unmarshal(bRead, &arbitraryMap) 77 if e != nil { 78 fmt.Println("key is possibly encryped, attempting to decrypt with $GCP_PASSWD") 79 80 passwd := os.Getenv("GCP_PASSWD") 81 if passwd == "" { 82 return errors.New("env GCP_PASSWD not set, cannot decrypt") 83 } 84 // Assume reading for decoding error is it's encrypted... attempt to decrypt 85 if gpg { 86 // use pipe to securly provide password 87 cmd := exec.Command("gpg", "--batch", "--passphrase-fd", "0", "--decrypt", "--output", decryptedKeyFileName, key) 88 writer, err := cmd.StdinPipe() 89 if err != nil { 90 return err 91 } 92 go func() { 93 defer writer.Close() 94 io.WriteString(writer, passwd) 95 }() 96 err = cmd.Run() 97 if err != nil { 98 return err 99 } 100 } else { 101 if decryptError := exec.Command("openssl", "aes-256-cbc", "-pass", "env:GCP_PASSWD", "-in", key, "-out", decryptedKeyFileName, "-d").Run(); decryptError != nil { 102 return decryptError 103 } 104 } 105 106 fmt.Println("decrypted key file to: ", decryptedKeyFileName) 107 key = decryptedKeyFileName 108 109 // Only remove *unecrypted* key file 110 defer func() { 111 key = filepath.Clean(key) 112 p, pe := filepath.Abs(key) 113 if pe != nil { 114 fmt.Println(pe) 115 } else { 116 key = p 117 } 118 119 fmt.Printf(` 120 removing key: %v 121 `, key) 122 if errRm := os.Remove(key); errRm != nil { 123 fmt.Println(errRm) 124 } 125 }() 126 } 127 128 ctx := context.Background() 129 client, err := storage.NewClient(ctx, option.WithServiceAccountFile(key)) 130 if err != nil { 131 return err 132 } 133 134 // Use glob to get matching file paths. 135 globs, e := filepath.Glob(files) 136 if e != nil { 137 return e 138 } 139 // Ensure there is something to upload 140 if len(globs) == 0 { 141 return errors.New("no files matching '-to' pattern were found") 142 } 143 // Upload each file 144 for _, f := range globs { 145 fi, e := os.Stat(f) 146 if e != nil { 147 return e 148 } 149 if fi.IsDir() { 150 fmt.Printf("%s is a directory, continuing", fi.Name()) 151 continue 152 } 153 // eg. 154 // to: builds.etcdevteam.com/go-ethereum/3.5.x 155 // file: ./dist/geth.zip 156 // 157 // Set bucket as first in separator-split path 158 // eg. builds.etcdevteam.com 159 bucket := strings.Split(filepath.ToSlash(to), "/")[0] 160 161 // Get relative path of 'to' based on 'bucket' 162 // eg. go-ethereum/3.5.x 163 object, relError := filepath.Rel(bucket, to) 164 if relError != nil { 165 return relError 166 } 167 168 // Append file to 'to' path. 169 // eg. go-ethereum/3.5.x/geth.zip 170 deployObject := filepath.Join(object, filepath.Base(f)) 171 // Ensure actual '/' [slash]es are used, because Windows will make them '\' [backslashes] 172 // and google won't folder-ize the path 173 deployObject = filepath.ToSlash(deployObject) 174 175 // Send it. 176 if deployError := writeToGCP(client, bucket, deployObject, f); deployError != nil { 177 return deployError 178 } 179 } 180 return nil 181 }