blob: 608da6ebb03bd1c8b0d855001a177eb6c8c84722 [file] [log] [blame] [edit]
// 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 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")
errGCENoExternalIP = verror.Register(pkgPath+".errGCENoExternalIP", verror.NoRetry, "{1:}{2:} gce instance does not have an external IP address")
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 a function to cancel initialization.
func InitCloudVM() (func(), error) {
mu.Lock()
if initialized {
mu.Unlock()
return func() {}, nil
}
initialized = true
cancel := make(chan struct{})
if os.Getenv(ref.EnvExpectGoogleComputeEngine) != "" {
defer mu.Unlock()
cloudvm.InitGCE(30*time.Second, cancel)
if !cloudvm.RunningOnGCE() {
return func() {}, verror.New(errNotGoogleComputeEngine, nil)
}
if cloudvm.ExternalIPAddress() == nil {
return func() {}, verror.New(errGCENoExternalIP, nil)
}
return func() {}, nil
}
done := make(chan struct{})
go func() {
cloudvm.InitGCE(time.Second, cancel)
cloudvm.InitAWS(time.Second, cancel)
mu.Unlock()
close(done)
}()
return func() {
close(cancel)
<-done
}, 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 !initialized {
panic("CloudVMPublicAddress called before InitCloudVM")
}
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
}