runtime: Fail when GCE metadata is inaccessible
When V23_EXPECT_GOOGLE_COMPUTE_ENGINE is set and non-empty, the runtime
will fail to initialize when the GCE metadata server is inaccessible or
some of its data cannot be retrieved.
When V23_EXPECT_GOOGLE_COMPUTE_ENGINE is not set (or is empty), the
previous behavior is preserved, i.e. we give up after 1 second and
assume we're not on GCE.
Production services cannot function properly when the metadata isn't
there. It's better to abort immediately than to keep running in a bad
state.
While at it, clean up the code around cloud VM metadata.
Fixes https://github.com/vanadium/issues/issues/1267
Change-Id: I933f97179b994c83460b2efe6658c8f098689531
diff --git a/envvar.go b/envvar.go
index b768d61..051028c 100644
--- a/envvar.go
+++ b/envvar.go
@@ -42,6 +42,10 @@
// to the url of the OAuth identity provider used by the principal
// seekblessings command.
EnvOAuthIdentityProvider = "V23_OAUTH_IDENTITY_PROVIDER"
+
+ // When EnvExpectGoogleComputeEngine is set and non-empty, the runtime
+ // initialization will fail if the GCE metadata is inaccessible.
+ EnvExpectGoogleComputeEngine = "V23_EXPECT_GOOGLE_COMPUTE_ENGINE"
)
// EnvNamespaceRoots returns the set of namespace roots to be used by the
diff --git a/runtime/factories/gce/gce.go b/runtime/factories/gce/gce.go
deleted file mode 100644
index a78018f..0000000
--- a/runtime/factories/gce/gce.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build linux
-
-// Package gce implements a RuntimeFactory for binaries that only run on Google
-// Compute Engine (GCE).
-package gce
-
-import (
- "flag"
- "fmt"
- "net"
-
- "v.io/v23"
- "v.io/v23/context"
- "v.io/v23/flow"
- "v.io/v23/rpc"
-
- "v.io/x/lib/netstate"
- "v.io/x/ref/lib/flags"
- "v.io/x/ref/runtime/internal"
- "v.io/x/ref/runtime/internal/gce"
- "v.io/x/ref/runtime/internal/lib/appcycle"
- grt "v.io/x/ref/runtime/internal/rt"
- "v.io/x/ref/runtime/protocols/lib/websocket"
- _ "v.io/x/ref/runtime/protocols/tcp"
- _ "v.io/x/ref/runtime/protocols/ws"
- _ "v.io/x/ref/runtime/protocols/wsh"
-)
-
-var commonFlags *flags.Flags
-
-func init() {
- v23.RegisterRuntimeFactory(Init)
- flow.RegisterUnknownProtocol("wsh", websocket.WSH{})
- commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Runtime, flags.Listen)
-}
-
-func Init(ctx *context.T) (v23.Runtime, *context.T, v23.Shutdown, error) {
- if err := internal.ParseFlagsAndConfigureGlobalLogger(commonFlags); err != nil {
- return nil, nil, nil, err
- }
-
- if !gce.RunningOnGCE() {
- return nil, nil, nil, fmt.Errorf("GCE profile used on a non-GCE system")
- }
-
- ac := appcycle.New()
-
- lf := commonFlags.ListenFlags()
- listenSpec := rpc.ListenSpec{
- Addrs: rpc.ListenAddrs(lf.Addrs),
- Proxy: lf.Proxy,
- }
-
- if ip, err := gce.ExternalIPAddress(); err != nil {
- ac.Shutdown()
- return nil, nil, nil, err
- } else {
- listenSpec.AddressChooser = netstate.AddressChooserFunc(func(network string, addrs []net.Addr) ([]net.Addr, error) {
- return []net.Addr{netstate.NewNetAddr("wsh", ip.String())}, nil
- })
- }
-
- runtime, ctx, shutdown, err := grt.Init(ctx, ac, nil, nil, nil, &listenSpec, nil, commonFlags.RuntimeFlags(), nil, 0)
- if err != nil {
- ac.Shutdown()
- return nil, nil, nil, err
- }
-
- ctx.VI(1).Infof("Initializing GCE RuntimeFactory.")
-
- runtimeFactoryShutdown := func() {
- ac.Shutdown()
- shutdown()
- }
- return runtime, ctx, runtimeFactoryShutdown, nil
-}
diff --git a/runtime/factories/roaming/roaming.go b/runtime/factories/roaming/roaming.go
index 32b596d..7c84342 100644
--- a/runtime/factories/roaming/roaming.go
+++ b/runtime/factories/roaming/roaming.go
@@ -50,6 +50,10 @@
return nil, nil, nil, err
}
+ if err := internal.InitCloudVM(); err != nil {
+ return nil, nil, nil, err
+ }
+
ac := appcycle.New()
discoveryFactory, err := dfactory.New(ctx)
if err != nil {
diff --git a/runtime/internal/address_chooser.go b/runtime/internal/address_chooser.go
index a317972..3a0ca64 100644
--- a/runtime/internal/address_chooser.go
+++ b/runtime/internal/address_chooser.go
@@ -6,57 +6,29 @@
import (
"net"
- "sync"
"v.io/v23/logging"
"v.io/v23/rpc"
)
type addressChooser struct {
- logger logging.Logger
- gcePublicAddressOnce sync.Once
- gcePublicAddress net.Addr
- ipChooser IPAddressChooser
-}
-
-func (c *addressChooser) setGCEPublicAddress() {
- c.gcePublicAddressOnce.Do(func() {
- if ipaddr := GCEPublicAddress(c.logger); ipaddr != nil {
- c.gcePublicAddress = ipaddr
- }
- })
+ logger logging.Logger
+ ipChooser IPAddressChooser
}
func (c *addressChooser) ChooseAddresses(protocol string, candidates []net.Addr) ([]net.Addr, error) {
- c.setGCEPublicAddress() // Blocks till the address is set
- if c.gcePublicAddress == nil {
- return c.ipChooser.ChooseAddresses(protocol, candidates)
+ if ipaddr := CloudVMPublicAddress(); ipaddr != nil {
+ return []net.Addr{ipaddr}, nil
}
- return []net.Addr{c.gcePublicAddress}, nil
+ return c.ipChooser.ChooseAddresses(protocol, candidates)
}
// NewAddressChooser will return the public IP of process if the process is
-// is being hosted by a cloud service provider (e.g. Google Compute Engine,
+// being hosted by a cloud service provider (e.g. Google Compute Engine,
// Amazon EC2), and if not will be the same as IPAddressChooser.
func NewAddressChooser(logger logging.Logger) rpc.AddressChooser {
if HasPublicIP(logger) {
return IPAddressChooser{}
}
- // Our address is private, so we test for running on GCE and for its 1:1 NAT
- // configuration. GCEPublicAddress returns a non-nil addr if we are
- // running on GCE/AWS.
- //
- // GCEPublicAddress can unforunately take up to 1 second to determine that the
- // external address (see https://github.com/vanadium/issues/issues/776).
- //
- // So NewAddressChooser fires it up in a goroutine and returns immediately,
- // thus avoiding any blockage till the AddressChooser is actually invoked.
- //
- // I apologize for the existence of this code! It is ugly, so if you have any
- // suggestions please do share. Ideally, the operation to "detect whether the
- // process is running under an Amazon EC2 instance" wouldn't block for a
- // timeout of 1 second and we can do away with this mess.
- ret := &addressChooser{logger: logger}
- go ret.setGCEPublicAddress()
- return ret
+ return &addressChooser{logger: logger}
}
diff --git a/runtime/internal/cloudvm/cloud_android.go b/runtime/internal/cloudvm/cloud_android.go
new file mode 100644
index 0000000..9761d95
--- /dev/null
+++ b/runtime/internal/cloudvm/cloud_android.go
@@ -0,0 +1,30 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build android
+
+package cloudvm
+
+import (
+ "net"
+ "time"
+)
+
+func InitGCE(time.Duration) {
+}
+
+func InitAWS(time.Duration) {
+}
+
+func RunningOnGCE() bool {
+ return false
+}
+
+func RunningOnAWS() bool {
+ return false
+}
+
+func ExternalIPAddress() net.IP {
+ return nil
+}
diff --git a/runtime/internal/cloudvm/cloud_linux.go b/runtime/internal/cloudvm/cloud_linux.go
new file mode 100644
index 0000000..ed9fa71
--- /dev/null
+++ b/runtime/internal/cloudvm/cloud_linux.go
@@ -0,0 +1,151 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,!android
+
+// Package cloudvm proides functions to test whether the current process is
+// running on Google Compute Engine or Amazon Web Services, and to extract
+// settings from this environment.
+package cloudvm
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "sync"
+ "time"
+
+ "v.io/x/ref/lib/stats"
+)
+
+// This URL returns the external IP address assigned to the local GCE instance.
+// If a HTTP GET request fails for any reason, this is not a GCE instance. If
+// the result of the GET request doesn't contain a "Metadata-Flavor: Google"
+// header, it is also not a GCE instance. The body of the document contains the
+// external IP address, if present. Otherwise, the body is empty.
+// See https://developers.google.com/compute/docs/metadata for details.
+const gceUrl = "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip"
+const awsUrl = "http://169.254.169.254/latest/meta-data/public-ipv4"
+
+var (
+ onceGCE sync.Once
+ onceAWS sync.Once
+ onGCE bool
+ onAWS bool
+ externalIP net.IP
+)
+
+func InitGCE(timeout time.Duration) {
+ onceGCE.Do(func() {
+ if onAWS {
+ return
+ }
+ gceTest(timeout)
+ })
+}
+
+func InitAWS(timeout time.Duration) {
+ onceAWS.Do(func() {
+ if onGCE {
+ return
+ }
+ awsTest(timeout)
+ })
+}
+
+func RunningOnGCE() bool {
+ return onGCE
+}
+
+func RunningOnAWS() bool {
+ return onAWS
+}
+
+// ExternalIPAddress returns the external IP address of this Google Compute
+// Engine or AWS instance, or nil if there is none. Must be called after
+// InitGCE / InitAWS.
+func ExternalIPAddress() net.IP {
+ return externalIP
+}
+
+func gceTest(timeout time.Duration) {
+ var err error
+ if externalIP, err = gceGetIP(gceUrl, timeout); err != nil {
+ return
+ }
+
+ vars := []struct {
+ name, url string
+ }{
+ {"system/gce/project-id", "http://metadata.google.internal/computeMetadata/v1/project/project-id"},
+ {"system/gce/zone", "http://metadata.google.internal/computeMetadata/v1/instance/zone"},
+ }
+ for _, v := range vars {
+ body, err := gceGetMeta(v.url, timeout)
+ if err != nil || body == "" {
+ return
+ }
+ stats.NewString(v.name).Set(body)
+ }
+ onGCE = true
+}
+
+func gceGetIP(url string, timeout time.Duration) (net.IP, error) {
+ body, err := gceGetMeta(url, timeout)
+ if err != nil {
+ return nil, err
+ }
+ return net.ParseIP(body), nil
+}
+
+func gceGetMeta(url string, timeout time.Duration) (string, error) {
+ client := &http.Client{Timeout: timeout}
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return "", err
+ }
+ req.Header.Add("Metadata-Flavor", "Google")
+ resp, err := client.Do(req)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return "", fmt.Errorf("http error: %d", resp.StatusCode)
+ }
+ if flavor := resp.Header["Metadata-Flavor"]; len(flavor) != 1 || flavor[0] != "Google" {
+ return "", fmt.Errorf("unexpected http header: %q", flavor)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return "", err
+ }
+ return string(body), nil
+}
+
+func awsTest(timeout time.Duration) {
+ client := &http.Client{Timeout: timeout}
+ req, err := http.NewRequest("GET", awsUrl, nil)
+ if err != nil {
+ return
+ }
+ resp, err := client.Do(req)
+ if err != nil {
+ return
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return
+ }
+ if server := resp.Header["Server"]; len(server) != 1 || server[0] != "EC2ws" {
+ return
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return
+ }
+ externalIP = net.ParseIP(string(body))
+ onAWS = true
+}
diff --git a/runtime/internal/gce/gce_other.go b/runtime/internal/cloudvm/cloud_other.go
similarity index 94%
rename from runtime/internal/gce/gce_other.go
rename to runtime/internal/cloudvm/cloud_other.go
index bfc9198..a4d8f58 100644
--- a/runtime/internal/gce/gce_other.go
+++ b/runtime/internal/cloudvm/cloud_other.go
@@ -4,7 +4,7 @@
// +build !linux
-package gce
+package cloudvm
// This package is a no-op on non-linux systems, but we still need at least
// one file in the package to keep go happy!
diff --git a/runtime/internal/gce/gce_test.go b/runtime/internal/cloudvm/cloud_test.go
similarity index 81%
rename from runtime/internal/gce/gce_test.go
rename to runtime/internal/cloudvm/cloud_test.go
index 0cfe65e..45f86f4 100644
--- a/runtime/internal/gce/gce_test.go
+++ b/runtime/internal/cloudvm/cloud_test.go
@@ -4,13 +4,14 @@
// +build linux,!android
-package gce
+package cloudvm
import (
"fmt"
"net"
"net/http"
"testing"
+ "time"
)
func startServer(t *testing.T) (net.Addr, func()) {
@@ -53,16 +54,16 @@
defer stop()
baseURL := "http://" + addr.String()
- if ip, err := gceTest(baseURL + "/404"); err == nil || ip != nil {
+ if ip, err := gceGetIP(baseURL+"/404", time.Second); err == nil || ip != nil {
t.Errorf("expected error, but not got nil")
}
- if ip, err := gceTest(baseURL + "/200_not_gce"); err == nil || ip != nil {
+ if ip, err := gceGetIP(baseURL+"/200_not_gce", time.Second); err == nil || ip != nil {
t.Errorf("expected error, but not got nil")
}
- if ip, err := gceTest(baseURL + "/gce_no_ip"); err != nil || ip != nil {
+ if ip, err := gceGetIP(baseURL+"/gce_no_ip", time.Second); err != nil || ip != nil {
t.Errorf("Unexpected result. Got (%v, %v), want nil:nil", ip, err)
}
- if ip, err := gceTest(baseURL + "/gce_with_ip"); err != nil || ip.String() != "1.2.3.4" {
+ if ip, err := gceGetIP(baseURL+"/gce_with_ip", time.Second); err != nil || ip.String() != "1.2.3.4" {
t.Errorf("Unexpected result. Got (%v, %v), want nil:1.2.3.4", ip, err)
}
}
diff --git a/runtime/internal/cloudvm_linux.go b/runtime/internal/cloudvm_linux.go
new file mode 100644
index 0000000..98cca46
--- /dev/null
+++ b/runtime/internal/cloudvm_linux.go
@@ -0,0 +1,77 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package internal
+
+import (
+ "net"
+ "os"
+ "sync"
+ "time"
+
+ "v.io/v23/verror"
+
+ "v.io/x/ref"
+ "v.io/x/ref/runtime/internal/cloudvm"
+)
+
+const pkgPath = "v.io/x/ref/runtime/internal"
+
+var (
+ errNotGoogleComputeEngine = verror.Register(pkgPath+".errNotGoogleComputeEngine", verror.NoRetry, "{1:}{2:} failed to access gce metadata")
+
+ initialized bool
+ mu sync.Mutex
+)
+
+// InitCloudVM initializes the CloudVM metadata.
+//
+// If EnvExpectGoogleComputeEngine is set, this function returns after the
+// initialization is done. Otherwise, the initialization is done asynchronously
+// and future calls to CloudVMPublicAddress() will block until the
+// initialization is complete.
+//
+// Returns an error if EnvExpectGoogleComputeEngine is set and the metadata
+// server is inaccessible.
+func InitCloudVM() error {
+ mu.Lock()
+ if initialized {
+ mu.Unlock()
+ return nil
+ }
+ initialized = true
+ if os.Getenv(ref.EnvExpectGoogleComputeEngine) != "" {
+ defer mu.Unlock()
+ cloudvm.InitGCE(30 * time.Second)
+ if !cloudvm.RunningOnGCE() {
+ return verror.New(errNotGoogleComputeEngine, nil)
+ }
+ return nil
+ }
+ go func() {
+ defer mu.Unlock()
+ cloudvm.InitGCE(time.Second)
+ cloudvm.InitAWS(time.Second)
+ }()
+ return nil
+}
+
+// CloudVMPublicAddress returns the public IP address of the Cloud VM instance
+// it is run from, or nil if run from anywhere else. The returned address is the
+// public address of a 1:1 NAT tunnel to this host.
+func CloudVMPublicAddress() *net.IPAddr {
+ mu.Lock()
+ defer mu.Unlock()
+ if !cloudvm.RunningOnGCE() && !cloudvm.RunningOnAWS() {
+ return nil
+ }
+ // Determine the IP address from VM's metadata
+ if ip := cloudvm.ExternalIPAddress(); ip != nil {
+ // 1:1 NAT case, our network config will not change.
+ return &net.IPAddr{IP: ip}
+ }
+ return nil
+}
diff --git a/runtime/internal/cloudvm_other.go b/runtime/internal/cloudvm_other.go
new file mode 100644
index 0000000..cdb707c
--- /dev/null
+++ b/runtime/internal/cloudvm_other.go
@@ -0,0 +1,23 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !linux
+
+package internal
+
+import (
+ "net"
+)
+
+// InitCloudVM initializes the CloudVM metadata.
+func InitCloudVM() error {
+ return nil
+}
+
+// CloudVMPublicAddress returns the public IP address of the Cloud VM instance
+// it is run from, or nil if run from anywhere else. The returned address is the
+// public address of a 1:1 NAT tunnel to this host.
+func CloudVMPublicAddress() *net.IPAddr {
+ return nil
+}
diff --git a/runtime/internal/gce/gce_android.go b/runtime/internal/gce/gce_android.go
deleted file mode 100644
index ce22de5..0000000
--- a/runtime/internal/gce/gce_android.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build android
-
-package gce
-
-import (
- "net"
-)
-
-func RunningOnGCE() bool {
- return false
-}
-
-func ExternalIPAddress() (net.IP, error) {
- panic("The GCE profile was unexpectedly used with android.")
-}
diff --git a/runtime/internal/gce/gce_linux.go b/runtime/internal/gce/gce_linux.go
deleted file mode 100644
index 73176ad..0000000
--- a/runtime/internal/gce/gce_linux.go
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build linux,!android
-
-// Package gce functions to test whether the current process is running on
-// Google Compute Engine, and to extract settings from this environment.
-// Any server that knows it will only ever run on GCE can import this Profile,
-// but in most cases, other Profiles will use the utility routines provided
-// by it to test to ensure that they are running on GCE and to obtain
-// metadata directly from its service APIs.
-//
-// TODO -- rename the package to "CloudVM" rather than gce, as it handles both gce
-// and AWS, and perhaps, in future, other cases of NAT'ed VMs.
-package gce
-
-import (
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "sync"
- "time"
-
- "v.io/x/ref/lib/stats"
-)
-
-// This URL returns the external IP address assigned to the local GCE instance.
-// If a HTTP GET request fails for any reason, this is not a GCE instance. If
-// the result of the GET request doesn't contain a "Metadata-Flavor: Google"
-// header, it is also not a GCE instance. The body of the document contains the
-// external IP address, if present. Otherwise, the body is empty.
-// See https://developers.google.com/compute/docs/metadata for details.
-const gceUrl = "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip"
-const awsUrl = "http://169.254.169.254/latest/meta-data/public-ipv4"
-
-// How long to wait for the HTTP request to return.
-const timeout = time.Second
-
-var (
- once sync.Once
- isGCEErr error
- externalIP net.IP
-)
-
-// RunningOnGCE returns true if the current process is running
-// on a Google Compute Engine instance.
-func RunningOnGCE() bool {
- once.Do(func() {
- externalIP, isGCEErr = gceTest(gceUrl)
- if isGCEErr == nil {
- gceExportVariables()
- } else {
- // try AWS instead
- externalIP, isGCEErr = awsTest(awsUrl)
- }
- })
- return isGCEErr == nil
-}
-
-// ExternalIPAddress returns the external IP address of this
-// Google Compute Engine instance, or nil if there is none. Must be
-// called after RunningOnGCE.
-func ExternalIPAddress() (net.IP, error) {
- return externalIP, isGCEErr
-}
-
-func gceTest(url string) (net.IP, error) {
- body, err := gceGetMeta(url, timeout)
- if err != nil {
- return nil, err
- }
- return net.ParseIP(body), nil
-}
-
-func gceExportVariables() {
- vars := []struct {
- name, url string
- }{
- {"system/gce/project-id", "http://metadata.google.internal/computeMetadata/v1/project/project-id"},
- {"system/gce/zone", "http://metadata.google.internal/computeMetadata/v1/instance/zone"},
- }
- for _, v := range vars {
- // At this point, we know we're on GCE. So, we might as well use a longer timeout.
- if body, err := gceGetMeta(v.url, 10*time.Second); err == nil {
- stats.NewString(v.name).Set(body)
- } else {
- stats.NewString(v.name).Set("unknown")
- }
- }
-}
-
-func gceGetMeta(url string, timeout time.Duration) (string, error) {
- client := &http.Client{Timeout: timeout}
- req, err := http.NewRequest("GET", url, nil)
- if err != nil {
- return "", err
- }
- req.Header.Add("Metadata-Flavor", "Google")
- resp, err := client.Do(req)
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
- if resp.StatusCode != 200 {
- return "", fmt.Errorf("http error: %d", resp.StatusCode)
- }
- if flavor := resp.Header["Metadata-Flavor"]; len(flavor) != 1 || flavor[0] != "Google" {
- return "", fmt.Errorf("unexpected http header: %q", flavor)
- }
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", err
- }
- return string(body), nil
-}
-
-func awsTest(url string) (net.IP, error) {
- client := &http.Client{Timeout: timeout}
- req, err := http.NewRequest("GET", url, nil)
- if err != nil {
- return nil, err
- }
- resp, err := client.Do(req)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- if resp.StatusCode != 200 {
- return nil, fmt.Errorf("http error: %d", resp.StatusCode)
- }
- if server := resp.Header["Server"]; len(server) != 1 || server[0] != "EC2ws" {
- return nil, fmt.Errorf("unexpected http Server header: %q", server)
- }
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, err
- }
- return net.ParseIP(string(body)), nil
-}
diff --git a/runtime/internal/gce_linux.go b/runtime/internal/gce_linux.go
deleted file mode 100644
index aaf489f..0000000
--- a/runtime/internal/gce_linux.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build linux
-
-package internal
-
-import (
- "net"
-
- "v.io/v23/logging"
-
- "v.io/x/ref/runtime/internal/gce"
-)
-
-// GCEPublicAddress returns the public IP address of the GCE instance
-// it is run from, or nil if run from anywhere else. The returned address
-// is the public address of a 1:1 NAT tunnel to this host.
-func GCEPublicAddress(log logging.Logger) *net.IPAddr {
- if !gce.RunningOnGCE() {
- return nil
- }
- var pub *net.IPAddr
- // Determine the IP address from GCE's metadata
- if ip, err := gce.ExternalIPAddress(); err != nil {
- log.Infof("failed to query GCE metadata: %s", err)
- } else {
- // 1:1 NAT case, our network config will not change.
- pub = &net.IPAddr{IP: ip}
- }
- if pub == nil {
- log.Infof("failed to determine public IP address to publish with")
- }
- return pub
-}
diff --git a/runtime/internal/gce_other.go b/runtime/internal/gce_other.go
deleted file mode 100644
index 4aea338..0000000
--- a/runtime/internal/gce_other.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !linux
-
-package internal
-
-import (
- "net"
-
- "v.io/v23/logging"
-)
-
-// GCEPublicAddress returns the public IP address of the GCE instance
-// it is run from, or nil if run from anywhere else. The returned address
-// is the public address of a 1:1 NAT tunnel to this host.
-func GCEPublicAddress(logging.Logger) *net.IPAddr {
- return nil
-}