github.com/coreos/mantle@v0.13.0/cmd/gangue/gangue.go (about)

     1  // Copyright 2017 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"net/http"
    21  	"net/url"
    22  	"os"
    23  	"path"
    24  
    25  	"github.com/spf13/cobra"
    26  
    27  	"github.com/coreos/mantle/auth"
    28  	"github.com/coreos/mantle/cli"
    29  	"github.com/coreos/mantle/sdk"
    30  )
    31  
    32  var (
    33  	root = &cobra.Command{
    34  		Use:   "gangue",
    35  		Short: "Google Storage download and verification tool",
    36  	}
    37  
    38  	get = &cobra.Command{
    39  		Use:   "get [url] [path]",
    40  		Short: "download and verify a file from Google Storage",
    41  		Run:   run,
    42  	}
    43  
    44  	gpgKeyFile, jsonKeyFile      string
    45  	keepSig, serviceAuth, verify bool
    46  )
    47  
    48  func init() {
    49  	bv := get.PersistentFlags().BoolVar
    50  	sv := get.PersistentFlags().StringVar
    51  
    52  	bv(&serviceAuth, "service-auth", false, "use non-interactive auth when running within GCE")
    53  	sv(&jsonKeyFile, "json-key", "", "use a service account's JSON key for authentication")
    54  	bv(&verify, "verify", true, "use GPG verification")
    55  	sv(&gpgKeyFile, "verify-key", "", "PGP public key file to verify signatures, or blank for the default key built into the program")
    56  	bv(&keepSig, "keep-sig", false, "keep the detached signature file on disk when successful")
    57  	root.AddCommand(get)
    58  }
    59  
    60  func validateGSURL(rawURL string) error {
    61  	parsedURL, err := url.Parse(rawURL)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	if parsedURL.Scheme != "gs" {
    66  		return fmt.Errorf("URL missing gs:// scheme: %v", rawURL)
    67  	}
    68  	if parsedURL.Host == "" {
    69  		return fmt.Errorf("URL missing bucket name %v", rawURL)
    70  	}
    71  	if parsedURL.Path == "" {
    72  		return fmt.Errorf("URL missing file path %v", rawURL)
    73  	}
    74  	if parsedURL.Path[len(parsedURL.Path)-1] == '/' {
    75  		return fmt.Errorf("URL must not be a directory path %v", rawURL)
    76  	}
    77  	return nil
    78  }
    79  
    80  func run(cmd *cobra.Command, args []string) {
    81  	var client *http.Client
    82  	var output, source string
    83  
    84  	if len(args) == 2 {
    85  		source = args[0]
    86  		output = args[1]
    87  	} else if len(args) == 1 {
    88  		source = args[0]
    89  		output = "."
    90  	} else {
    91  		fmt.Fprintf(os.Stderr, "Expected one or two arguments\n")
    92  		os.Exit(1)
    93  	}
    94  
    95  	// Perform some basic sanity checks on the options
    96  	err := validateGSURL(source)
    97  	if err != nil {
    98  		fmt.Fprintf(os.Stderr, "%v\n", err)
    99  		os.Exit(1)
   100  	}
   101  	if output == "" {
   102  		output = "."
   103  	}
   104  
   105  	// If the output path exists and is a directory, keep the file name
   106  	if stat, err := os.Stat(output); err == nil && stat.IsDir() {
   107  		output = path.Join(output, path.Base(source))
   108  	}
   109  
   110  	// Authenticate with Google
   111  	if serviceAuth {
   112  		client = auth.GoogleServiceClient()
   113  	} else if jsonKeyFile != "" {
   114  		b, err := ioutil.ReadFile(jsonKeyFile)
   115  		if err != nil {
   116  			fmt.Fprintf(os.Stderr, "%v\n", err)
   117  			os.Exit(1)
   118  		}
   119  		client, err = auth.GoogleClientFromJSONKey(b)
   120  	} else {
   121  		client, err = auth.GoogleClient()
   122  	}
   123  	if err != nil {
   124  		fmt.Fprintf(os.Stderr, "%v\n", err)
   125  		os.Exit(1)
   126  	}
   127  
   128  	// Download the file and verify it (unless disabled)
   129  	if verify {
   130  		err = sdk.UpdateSignedFile(output, source, client, gpgKeyFile)
   131  		if err == nil && !keepSig {
   132  			err = os.Remove(output + ".sig")
   133  		}
   134  	} else {
   135  		err = sdk.UpdateFile(output, source, client)
   136  	}
   137  	if err != nil {
   138  		fmt.Fprintf(os.Stderr, "%v\n", err)
   139  		os.Exit(1)
   140  	}
   141  }
   142  
   143  func main() {
   144  	cli.Execute(root)
   145  }