github.com/google/cloudprober@v0.11.3/common/file/file.go (about)

     1  // Copyright 2020 The Cloudprober Authors.
     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  /*
    16  Package file implements utilities to read files from various backends.
    17  */
    18  package file
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"net/http"
    26  	"os"
    27  	"strings"
    28  	"time"
    29  
    30  	"golang.org/x/oauth2/google"
    31  )
    32  
    33  type readFunc func(path string) ([]byte, error)
    34  type modTimeFunc func(path string) (time.Time, error)
    35  
    36  var prefixToReadfunc = map[string]readFunc{
    37  	"gs://": readFileFromGCS,
    38  }
    39  
    40  var prefixToModTimeFunc = map[string]modTimeFunc{
    41  	"gs://": modTimeGCS,
    42  }
    43  
    44  func readFileFromGCS(objectPath string) ([]byte, error) {
    45  	hc, err := google.DefaultClient(context.Background())
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	objURL := "https://storage.googleapis.com/" + objectPath
    51  	res, err := hc.Get(objURL)
    52  
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	if res.StatusCode != http.StatusOK {
    58  		return nil, fmt.Errorf("got error while retrieving GCS object, http status: %s, status code: %d", res.Status, res.StatusCode)
    59  	}
    60  
    61  	defer res.Body.Close()
    62  	return ioutil.ReadAll(res.Body)
    63  }
    64  
    65  func modTimeGCS(objectPath string) (time.Time, error) {
    66  	return time.Time{}, errors.New("mod-time is not implemented for GCS files yet")
    67  }
    68  
    69  // ReadFile returns file contents as a slice of bytes. It's similar to ioutil's
    70  // ReadFile, but includes support for files on non-disk locations. For example,
    71  // files with paths starting with gs:// are assumed to be on GCS, and are read
    72  // from GCS.
    73  func ReadFile(fname string) ([]byte, error) {
    74  	for prefix, f := range prefixToReadfunc {
    75  		if strings.HasPrefix(fname, prefix) {
    76  			return f(fname[len(prefix):])
    77  		}
    78  	}
    79  	return ioutil.ReadFile(fname)
    80  }
    81  
    82  // ModTime returns file's modified timestamp.
    83  func ModTime(fname string) (time.Time, error) {
    84  	for prefix, f := range prefixToModTimeFunc {
    85  		if strings.HasPrefix(fname, prefix) {
    86  			return f(fname[len(prefix):])
    87  		}
    88  	}
    89  
    90  	statInfo, err := os.Stat(fname)
    91  	if err != nil {
    92  		return time.Time{}, err
    93  	}
    94  	return statInfo.ModTime(), nil
    95  }