You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

142 lines
3.8 KiB

  1. /*
  2. *
  3. * Copyright 2018 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. package alts
  19. import (
  20. "context"
  21. "errors"
  22. "fmt"
  23. "io"
  24. "io/ioutil"
  25. "log"
  26. "os"
  27. "os/exec"
  28. "regexp"
  29. "runtime"
  30. "strings"
  31. "google.golang.org/grpc/peer"
  32. )
  33. const (
  34. linuxProductNameFile = "/sys/class/dmi/id/product_name"
  35. windowsCheckCommand = "powershell.exe"
  36. windowsCheckCommandArgs = "Get-WmiObject -Class Win32_BIOS"
  37. powershellOutputFilter = "Manufacturer"
  38. windowsManufacturerRegex = ":(.*)"
  39. )
  40. type platformError string
  41. func (k platformError) Error() string {
  42. return fmt.Sprintf("%s is not supported", string(k))
  43. }
  44. var (
  45. // The following two variables will be reassigned in tests.
  46. runningOS = runtime.GOOS
  47. manufacturerReader = func() (io.Reader, error) {
  48. switch runningOS {
  49. case "linux":
  50. return os.Open(linuxProductNameFile)
  51. case "windows":
  52. cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs)
  53. out, err := cmd.Output()
  54. if err != nil {
  55. return nil, err
  56. }
  57. for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
  58. if strings.HasPrefix(line, powershellOutputFilter) {
  59. re := regexp.MustCompile(windowsManufacturerRegex)
  60. name := re.FindString(line)
  61. name = strings.TrimLeft(name, ":")
  62. return strings.NewReader(name), nil
  63. }
  64. }
  65. return nil, errors.New("cannot determine the machine's manufacturer")
  66. default:
  67. return nil, platformError(runningOS)
  68. }
  69. }
  70. vmOnGCP bool
  71. )
  72. // isRunningOnGCP checks whether the local system, without doing a network request is
  73. // running on GCP.
  74. func isRunningOnGCP() bool {
  75. manufacturer, err := readManufacturer()
  76. if err != nil {
  77. log.Fatalf("failure to read manufacturer information: %v", err)
  78. }
  79. name := string(manufacturer)
  80. switch runningOS {
  81. case "linux":
  82. name = strings.TrimSpace(name)
  83. return name == "Google" || name == "Google Compute Engine"
  84. case "windows":
  85. name = strings.Replace(name, " ", "", -1)
  86. name = strings.Replace(name, "\n", "", -1)
  87. name = strings.Replace(name, "\r", "", -1)
  88. return name == "Google"
  89. default:
  90. log.Fatal(platformError(runningOS))
  91. }
  92. return false
  93. }
  94. func readManufacturer() ([]byte, error) {
  95. reader, err := manufacturerReader()
  96. if err != nil {
  97. return nil, err
  98. }
  99. if reader == nil {
  100. return nil, errors.New("got nil reader")
  101. }
  102. manufacturer, err := ioutil.ReadAll(reader)
  103. if err != nil {
  104. return nil, fmt.Errorf("failed reading %v: %v", linuxProductNameFile, err)
  105. }
  106. return manufacturer, nil
  107. }
  108. // AuthInfoFromContext extracts the alts.AuthInfo object from the given context,
  109. // if it exists. This API should be used by gRPC server RPC handlers to get
  110. // information about the communicating peer. For client-side, use grpc.Peer()
  111. // CallOption.
  112. func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) {
  113. p, ok := peer.FromContext(ctx)
  114. if !ok {
  115. return nil, errors.New("no Peer found in Context")
  116. }
  117. return AuthInfoFromPeer(p)
  118. }
  119. // AuthInfoFromPeer extracts the alts.AuthInfo object from the given peer, if it
  120. // exists. This API should be used by gRPC clients after obtaining a peer object
  121. // using the grpc.Peer() CallOption.
  122. func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) {
  123. altsAuthInfo, ok := p.AuthInfo.(AuthInfo)
  124. if !ok {
  125. return nil, errors.New("no alts.AuthInfo found in Peer")
  126. }
  127. return altsAuthInfo, nil
  128. }