github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/googlecloud/googlecloud.go (about)

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  // Package googlecloud contains internal helpful functions for google cloud.
    20  package googlecloud
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  	"io"
    26  	"io/ioutil"
    27  	"os"
    28  	"os/exec"
    29  	"regexp"
    30  	"runtime"
    31  	"strings"
    32  	"sync"
    33  
    34  	"github.com/hxx258456/ccgo/grpc/grpclog"
    35  	internalgrpclog "github.com/hxx258456/ccgo/grpc/internal/grpclog"
    36  )
    37  
    38  const (
    39  	linuxProductNameFile     = "/sys/class/dmi/id/product_name"
    40  	windowsCheckCommand      = "powershell.exe"
    41  	windowsCheckCommandArgs  = "Get-WmiObject -Class Win32_BIOS"
    42  	powershellOutputFilter   = "Manufacturer"
    43  	windowsManufacturerRegex = ":(.*)"
    44  
    45  	logPrefix = "[googlecloud]"
    46  )
    47  
    48  var (
    49  	// The following two variables will be reassigned in tests.
    50  	runningOS          = runtime.GOOS
    51  	manufacturerReader = func() (io.Reader, error) {
    52  		switch runningOS {
    53  		case "linux":
    54  			return os.Open(linuxProductNameFile)
    55  		case "windows":
    56  			cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs)
    57  			out, err := cmd.Output()
    58  			if err != nil {
    59  				return nil, err
    60  			}
    61  			for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
    62  				if strings.HasPrefix(line, powershellOutputFilter) {
    63  					re := regexp.MustCompile(windowsManufacturerRegex)
    64  					name := re.FindString(line)
    65  					name = strings.TrimLeft(name, ":")
    66  					return strings.NewReader(name), nil
    67  				}
    68  			}
    69  			return nil, errors.New("cannot determine the machine's manufacturer")
    70  		default:
    71  			return nil, fmt.Errorf("%s is not supported", runningOS)
    72  		}
    73  	}
    74  
    75  	vmOnGCEOnce sync.Once
    76  	vmOnGCE     bool
    77  
    78  	logger = internalgrpclog.NewPrefixLogger(grpclog.Component("googlecloud"), logPrefix)
    79  )
    80  
    81  // OnGCE returns whether the client is running on GCE.
    82  //
    83  // It provides similar functionality as metadata.OnGCE from the cloud library
    84  // package. We keep this to avoid depending on the cloud library module.
    85  func OnGCE() bool {
    86  	vmOnGCEOnce.Do(func() {
    87  		vmOnGCE = isRunningOnGCE()
    88  	})
    89  	return vmOnGCE
    90  }
    91  
    92  // isRunningOnGCE checks whether the local system, without doing a network request is
    93  // running on GCP.
    94  func isRunningOnGCE() bool {
    95  	manufacturer, err := readManufacturer()
    96  	if err != nil {
    97  		logger.Infof("failed to read manufacturer %v, returning OnGCE=false", err)
    98  		return false
    99  	}
   100  	name := string(manufacturer)
   101  	switch runningOS {
   102  	case "linux":
   103  		name = strings.TrimSpace(name)
   104  		return name == "Google" || name == "Google Compute Engine"
   105  	case "windows":
   106  		name = strings.Replace(name, " ", "", -1)
   107  		name = strings.Replace(name, "\n", "", -1)
   108  		name = strings.Replace(name, "\r", "", -1)
   109  		return name == "Google"
   110  	default:
   111  		return false
   112  	}
   113  }
   114  
   115  func readManufacturer() ([]byte, error) {
   116  	reader, err := manufacturerReader()
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  	if reader == nil {
   121  		return nil, errors.New("got nil reader")
   122  	}
   123  	manufacturer, err := ioutil.ReadAll(reader)
   124  	if err != nil {
   125  		return nil, fmt.Errorf("failed reading %v: %v", linuxProductNameFile, err)
   126  	}
   127  	return manufacturer, nil
   128  }