// If we're not running on GCE (e.g. dev mode on localhost) and have // no other way to get the info, the error value is is errNoRefresh. func (h *DeployHandler) authenticatedClient() (project string, hc *http.Client, err error) { project = os.Getenv("CAMLI_GCE_PROJECT") accountFile := os.Getenv("CAMLI_GCE_SERVICE_ACCOUNT") if project != "" && accountFile != "" { data, errr := ioutil.ReadFile(accountFile) err = errr if err != nil { return } jwtConf, errr := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/compute.readonly") err = errr if err != nil { return } hc = jwtConf.Client(context.Background()) return } if !metadata.OnGCE() { err = errNoRefresh return } project, _ = metadata.ProjectID() hc, err = google.DefaultClient(oauth2.NoContext) return project, hc, err }
func init() { if !metadata.OnGCE() { return } client, err := googlestorage.NewServiceClient() wkfs.RegisterFS("/gcs/", &gcsFS{client, err}) }
func NewAuthTokenProvider(expectedAuthScope string) (AuthTokenProvider, error) { // Retry OnGCE call for 15 seconds before declaring failure. onGCE := false for start := time.Now(); time.Since(start) < 15*time.Second; time.Sleep(time.Second) { if metadata.OnGCE() { onGCE = true break } } // Only support GCE for now. if !onGCE { return nil, fmt.Errorf("authorization to GCE is currently only supported on GCE") } // Check for required auth scopes err := verifyAuthScope(expectedAuthScope) if err != nil { return nil, err } t := &realAuthTokenProvider{ RWMutex: sync.RWMutex{}, } go t.refreshTokenWhenExpires() return t, nil }
func maybeRemapCloudSQL(host string) (out string, err error) { if !strings.HasSuffix(host, cloudSQLSuffix) { return host, nil } inst := strings.TrimSuffix(host, cloudSQLSuffix) if !metadata.OnGCE() { return "", errors.New("CloudSQL support only available when running on Google Compute Engine.") } proj, err := metadata.ProjectID() if err != nil { return "", fmt.Errorf("Failed to lookup GCE project ID: %v", err) } admin, _ := sqladmin.New(oauth2.NewClient(context.Background(), google.ComputeTokenSource(""))) listRes, err := admin.Instances.List(proj).Do() if err != nil { return "", fmt.Errorf("error enumerating Cloud SQL instances: %v", err) } for _, it := range listRes.Items { if !strings.EqualFold(it.Instance, inst) { continue } js, _ := json.Marshal(it) log.Printf("Found Cloud SQL instance %s: %s", inst, js) for _, ipm := range it.IpAddresses { return ipm.IpAddress, nil } return "", fmt.Errorf("No external IP address for Cloud SQL instances %s", inst) } var found []string for _, it := range listRes.Items { found = append(found, it.Instance) } return "", fmt.Errorf("Cloud SQL instance %q not found. Found: %q", inst, found) }
func init() { if !metadata.OnGCE() { return } hc, err := google.DefaultClient(oauth2.NoContext) if err != nil { registerBrokenFS(fmt.Errorf("could not get http client for context: %v", err)) return } projID, err := metadata.ProjectID() if projID == "" || err != nil { registerBrokenFS(fmt.Errorf("could not get GCE project ID: %v", err)) return } ctx := cloud.NewContext(projID, hc) sc, err := storage.NewClient(ctx) if err != nil { registerBrokenFS(fmt.Errorf("could not get cloud storage client: %v", err)) return } wkfs.RegisterFS("/gcs/", &gcsFS{ ctx: ctx, sc: sc, }) }
// Gets the IP of the specified GCE instance. func GetGceIp(hostname string) (string, error) { if hostname == "localhost" { return "127.0.0.1", nil } args := []string{"compute"} args = append(args, getProjectFlag()...) args = append(args, "instances", "describe") args = append(args, getZoneFlag()...) args = append(args, hostname) out, err := exec.Command("gcloud", args...).CombinedOutput() if err != nil { return "", fmt.Errorf("failed to get instance information for %q with error %v and output %s", hostname, err, string(out)) } // Use the internal IP within GCE and the external one outside. var matches []string if metadata.OnGCE() { matches = gceInternalIpRegexp.FindStringSubmatch(string(out)) } else { matches = gceExternalIpRegexp.FindStringSubmatch(string(out)) } if len(matches) == 0 { return "", fmt.Errorf("failed to find IP from output %q", string(out)) } return matches[1], nil }
// Returns an implementation of a Google Cloud Logging (GCL) sink. func new() (sink_api.ExternalSink, error) { // TODO: Retry OnGCE call for ~15 seconds before declaring failure. time.Sleep(3 * time.Second) // Only support GCE for now. if !metadata.OnGCE() { return nil, fmt.Errorf("The Google Cloud Logging (GCL) sink failed to start: this process must be running on Google Compute Engine (GCE)") } // Detect project ID projectId, err := metadata.ProjectID() if err != nil { return nil, err } glog.Infof("Project ID for GCL sink is: %q\r\n", projectId) // Check for required auth scopes err = gce.VerifyAuthScope(GCLAuthScope) if err != nil { return nil, err } impl := &gclSink{ projectId: projectId, httpClient: &http.Client{}, } // Get an initial token. err = impl.refreshToken() if err != nil { return nil, err } return impl, nil }
func detectGCE() { if !metadata.OnGCE() { return } v, _ := metadata.InstanceAttributeValue("camlistore-config-dir") isGCE = v != "" }
func (cs computeSource) Token() (*oauth2.Token, error) { if !metadata.OnGCE() { return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE") } acct := cs.account if acct == "" { acct = "default" } tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token") if err != nil { return nil, err } var res struct { AccessToken string `json:"access_token"` ExpiresInSec int `json:"expires_in"` TokenType string `json:"token_type"` } err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res) if err != nil { return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err) } if res.ExpiresInSec == 0 || res.AccessToken == "" { return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata") } return &oauth2.Token{ AccessToken: res.AccessToken, TokenType: res.TokenType, Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second), }, nil }
// metadataValue returns the GCE metadata instance value for the given key. // If the metadata is not defined, the returned string is empty. // // If not running on GCE, it falls back to using environment variables // for local development. func metadataValue(key string) string { // The common case (on GCE, but not in Kubernetes): if metadata.OnGCE() && !inKube { v, err := metadata.InstanceAttributeValue(key) if _, notDefined := err.(metadata.NotDefinedError); notDefined { return "" } if err != nil { log.Fatalf("metadata.InstanceAttributeValue(%q): %v", key, err) } return v } // Else allow use of environment variables to fake // metadata keys, for Kubernetes pods or local testing. envKey := "META_" + strings.Replace(key, "-", "_", -1) v := os.Getenv(envKey) // Respect curl-style '@' prefix to mean the rest is a filename. if strings.HasPrefix(v, "@") { slurp, err := ioutil.ReadFile(v[1:]) if err != nil { log.Fatalf("Error reading file for GCEMETA_%v: %v", key, err) } return string(slurp) } if v == "" { log.Printf("Warning: not running on GCE, and no %v environment variable defined", envKey) } return v }
func newInstance() *Instance { var i = new(Instance) if !metadata.OnGCE() { i.Error = "Not running on GCE" return i } a := &assigner{} i.Id = a.assign(metadata.InstanceID) i.Zone = a.assign(metadata.Zone) i.Name = a.assign(metadata.InstanceName) i.Hostname = a.assign(metadata.Hostname) i.Project = a.assign(metadata.ProjectID) i.InternalIP = a.assign(metadata.InternalIP) i.ExternalIP = a.assign(metadata.ExternalIP) // read current POD and Namespace i.POD = os.Getenv("MY_POD_NAME") i.Namespace = os.Getenv("MY_POD_NAMESPACE") if a.err != nil { i.Error = a.err.Error() } return i }
// newClient creates http.Client with a jwt service account when // jsonFile flag is specified, otherwise by obtaining the GCE service // account's access token. func newClient(jsonFile string) (*http.Client, error) { if jsonFile != "" { jsonKey, err := ioutil.ReadFile(jsonFile) if err != nil { return nil, err } conf, err := google.JWTConfigFromJSON(jsonKey, pubsub.ScopePubSub) if err != nil { return nil, err } return conf.Client(oauth2.NoContext), nil } if metadata.OnGCE() { c := &http.Client{ Transport: &oauth2.Transport{ Source: google.ComputeTokenSource(""), }, } if *projID == "" { projectID, err := metadata.ProjectID() if err != nil { return nil, fmt.Errorf("ProjectID failed, %v", err) } *projID = projectID } return c, nil } return nil, errors.New("Could not create an authenticated client.") }
func EnsureOnGCE() error { for start := time.Now(); time.Since(start) < waitForGCETimeout; time.Sleep(waitForGCEInterval) { glog.Infof("Waiting for GCE metadata to be available") if metadata.OnGCE() { return nil } } return fmt.Errorf("not running on GCE") }
func checkInProduction() bool { if !metadata.OnGCE() { return false } proj, _ := metadata.ProjectID() inst, _ := metadata.InstanceName() log.Printf("Running on GCE: %v / %v", proj, inst) return proj == "camlistore-website" && inst == "camweb" }
func newLoggerConfig() *loggerConfig { c := &loggerConfig{ gceAccount: "default", logsID: "monitoring_proxy", } if metadata.OnGCE() { c.preloadFromGCEMetadata() } return c }
func ip(w http.ResponseWriter, r *http.Request) { ip := "127.0.0.1" if metadata.OnGCE() { var err error ip, err = metadata.InternalIP() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } w.Write([]byte(ip)) }
func buildletURL() string { if !metadata.OnGCE() { if v := os.Getenv("META_BUILDLET_BINARY_URL"); v != "" { return v } sleepFatalf("Not on GCE, and no META_BUILDLET_BINARY_URL specified.") } v, err := metadata.InstanceAttributeValue(attr) if err != nil { sleepFatalf("Failed to look up %q attribute value: %v", attr, err) } return v }
func TestWriteRead(t *testing.T) { if !metadata.OnGCE() { t.Skipf("Not testing on GCE") } if *flagBucket == "" { t.Skipf("No bucket specified") } ctx := context.Background() cl, err := storage.NewClient(ctx) list, err := cl.Bucket(*flagBucket).List(ctx, nil) if err != nil { t.Fatal(err) } if len(list.Results) > 0 { t.Fatalf("Bucket %v is not empty, aborting test.", *flagBucket) } filename := "camli-gcs_test.txt" defer func() { if err := cl.Bucket(*flagBucket).Object(filename).Delete(ctx); err != nil { t.Fatalf("error while cleaning up: %v", err) } }() // Write to camli-gcs_test.txt gcsPath := "/gcs/" + *flagBucket + "/" + filename f, err := wkfs.Create(gcsPath) if err != nil { t.Fatalf("error creating %v: %v", gcsPath, err) } data := "Hello World" if _, err := io.Copy(f, strings.NewReader(data)); err != nil { t.Fatalf("error writing to %v: %v", gcsPath, err) } if err := f.Close(); err != nil { t.Fatalf("error closing %v: %v", gcsPath, err) } // Read back from camli-gcs_test.txt g, err := wkfs.Open(gcsPath) if err != nil { t.Fatalf("error opening %v: %v", gcsPath, err) } defer g.Close() var buf bytes.Buffer if _, err := io.Copy(&buf, g); err != nil { t.Fatalf("error reading %v: %v", gcsPath, err) } if buf.String() != data { t.Fatalf("error with %v contents: got %v, wanted %v", gcsPath, buf.String(), data) } }
func initGCE() error { initGCECalled = true // Use the staging project if not on GCE. This assumes the DefaultTokenSource // credential used below has access to that project. if !metadata.OnGCE() { projectID = stagingProjectID } var err error projectID, err = metadata.ProjectID() if err != nil { return fmt.Errorf("failed to get current GCE ProjectID: %v", err) } inStaging = projectID == stagingProjectID if inStaging { log.Printf("Running in staging cluster (%q)", projectID) } tokenSource, _ = google.DefaultTokenSource(oauth2.NoContext) httpClient := oauth2.NewClient(oauth2.NoContext, tokenSource) serviceCtx = cloud.NewContext(projectID, httpClient) projectZone, err = metadata.Get("instance/zone") if err != nil || projectZone == "" { return fmt.Errorf("failed to get current GCE zone: %v", err) } // Convert the zone from "projects/1234/zones/us-central1-a" to "us-central1-a". projectZone = path.Base(projectZone) if !hasComputeScope() { return errors.New("The coordinator is not running with access to read and write Compute resources. VM support disabled.") } projectRegion = projectZone[:strings.LastIndex(projectZone, "-")] // "us-central1" externalIP, err = metadata.ExternalIP() if err != nil { return fmt.Errorf("ExternalIP: %v", err) } computeService, _ = compute.New(httpClient) errTryDeps = checkTryBuildDeps() if errTryDeps != nil { log.Printf("TryBot builders disabled due to error: %v", errTryDeps) } else { log.Printf("TryBot builders enabled.") } go gcePool.pollQuotaLoop() return nil }
func main() { flag.Parse() s := NewServer(*resolverAddr, *refreshPeriod) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" && *anusEnabled { anus(w, r) return } s.ServeHTTP(w, r) }) if *httpsAddr != "" { if !metadata.OnGCE() { log.Fatal("Not on GCE. HTTPS only supported on GCE using letsencrypt. Exiting.") } v := func(key string) string { v, err := metadata.InstanceAttributeValue(key) if err != nil { log.Fatalf("Couldn't read %q metadata value: %v", key, err) } return v } var m letsencrypt.Manager if err := letscloud.Cache(&m, v("letscloud-get-url"), v("letscloud-put-url")); err != nil { log.Fatal(err) } srv := &http.Server{ Addr: *httpsAddr, TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, } go func() { log.Println("Starting HTTPS server on", *httpsAddr) log.Fatal(srv.ListenAndServeTLS("", "")) }() } if *httpAddr != "" { var h http.Handler if *redirectHTTP { h = http.HandlerFunc(letsencrypt.RedirectHTTP) } go func() { log.Println("Starting HTTP server on", *httpAddr) log.Fatal(http.ListenAndServe(*httpAddr, h)) }() } select {} }
func initGCP() { initGCPOnce.Do(func() { onGCE = metadata.OnGCE() if onGCE { // These will fail on instances if the metadata service is // down or the client is compiled with an API version that // has been removed. Since these are not vital, let's ignore // them and make their fields in the dockeLogEntry ,omitempty projectID, _ = metadata.ProjectID() zone, _ = metadata.Zone() instanceName, _ = metadata.InstanceName() instanceID, _ = metadata.InstanceID() } }) }
// Populate fills the Config with default values derived from the environment. // Missing values will not be set. // // This includes: // - GCE metadata querying. func (o *ClientOptions) Populate() { if metadata.OnGCE() { get := func(f func() (string, error), val *string) { if v, err := f(); err == nil { *val = v } } o.ServiceName = GCEService get(metadata.ProjectID, &o.ProjectID) get(metadata.InstanceName, &o.ResourceType) get(metadata.InstanceID, &o.ResourceID) get(metadata.Zone, &o.Zone) } }
func hasScope(want string) bool { if !metadata.OnGCE() { return false } scopes, err := metadata.Scopes("default") if err != nil { log.Printf("failed to query metadata default scopes: %v", err) return false } for _, v := range scopes { if v == want { return true } } return false }
func init() { // Read Config file config = Config{} file, err := os.Open("conf.json") if err != nil { fmt.Println("No config file found. Using Defaults") config.PingPeriod = 60 config.EmailThrottle = 5 } else { decoder := json.NewDecoder(file) err = decoder.Decode(&config) check(err) } // Check if running on GCE if metadata.OnGCE() { if Debug { fmt.Println("Running on GCE. Pulling attributes.") } gce = true } else { if Debug { fmt.Println("Not running on GCE.") } gce = false } // init loggers var writer io.Writer if len(config.LogFileName) > 0 { // Create Directory // os.MkdirAll(, 0777) logFile, err := os.OpenFile(config.LogFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { fmt.Println("Error opening log file: ", err) writer = os.Stdout } else { defer logFile.Close() writer = logFile } } else { writer = os.Stdout } InfoLog = log.New(writer, "INFO: ", log.LstdFlags) ErrorLog = log.New(writer, "ERROR: ", log.LstdFlags) }
func defaultListenAddr() string { if runtime.GOOS == "darwin" { // Darwin will never run on GCE, so let's always // listen on a high port (so we don't need to be // root). return ":5936" } if !metadata.OnGCE() { return "localhost:5936" } // In production, default to port 80 or 443, depending on // whether TLS is configured. if metadataValue("tls-cert") != "" { return ":443" } return ":80" }
// DefaultTokenSource is a token source that uses // "Application Default Credentials". // // It looks for credentials in the following places, // preferring the first location found: // // 1. A JSON file whose path is specified by the // GOOGLE_APPLICATION_CREDENTIALS environment variable. // 2. A JSON file in a location known to the gcloud command-line tool. // On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. // On other systems, $HOME/.config/gcloud/application_default_credentials.json. // 3. On Google App Engine it uses the appengine.AccessToken function. // 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches // credentials from the metadata server. // (In this final case any provided scopes are ignored.) // // For more details, see: // https://developers.google.com/accounts/docs/application-default-credentials // func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) { // First, try the environment variable. const envVar = "GOOGLE_APPLICATION_CREDENTIALS" if filename := os.Getenv(envVar); filename != "" { ts, err := tokenSourceFromFile(ctx, filename, scope) if err != nil { return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err) } return ts, nil } // Second, try a well-known file. filename := wellKnownFile() _, err := os.Stat(filename) if err == nil { ts, err2 := tokenSourceFromFile(ctx, filename, scope) if err2 == nil { return ts, nil } err = err2 } else if os.IsNotExist(err) { err = nil // ignore this error } if err != nil { return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) } // Third, if we're on Google App Engine use those credentials. if appengineTokenFunc != nil && !appengineVM { return AppEngineTokenSource(ctx, scope...), nil } // Fourth, if we're on Google Compute Engine use the metadata server. if metadata.OnGCE() { return ComputeTokenSource(""), nil } // None are found; return helpful error. const url = "https://developers.google.com/accounts/docs/application-default-credentials" return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) }
func (cmo *CloudMonitoringOutput) Init(config interface{}) (err error) { cmo.conf = config.(*CloudMonitoringConfig) if metadata.OnGCE() { if cmo.conf.ProjectId == "" { if cmo.conf.ProjectId, err = metadata.ProjectID(); err != nil { return } } if cmo.conf.ResourceId == "" { if cmo.conf.ResourceId, err = metadata.InstanceID(); err != nil { return } } if cmo.conf.Zone == "" { if cmo.conf.Zone, err = metadata.Get("instance/zone"); err != nil { return } } } if cmo.conf.ProjectId == "" { return errors.New("ProjectId cannot be blank") } cmo.batchChan = make(chan MonitoringBatch) cmo.backChan = make(chan []*cloudmonitoring.TimeseriesPoint, 2) cmo.outputExit = make(chan error) if cmo.client, err = google.DefaultClient(oauth2.NoContext, cloudmonitoring.MonitoringScope); err != nil { return } if cmo.service, err = cloudmonitoring.New(cmo.client); err != nil { return } r := &cloudmonitoring.ListMetricDescriptorsRequest{Kind: "cloudmonitoring#listMetricDescriptorsRequest"} _, err = cmo.service.MetricDescriptors.List(cmo.conf.ProjectId, r).Do() if err != nil { log.Print("Init CloudMonitoringOutput Error: %v", err) } return }
func newInstance() *Instance { var i = new(Instance) if !metadata.OnGCE() { i.Error = "Not running on GCE" return i } a := &assigner{} i.Id = a.assign(metadata.InstanceID) i.Zone = a.assign(metadata.Zone) i.Name = a.assign(metadata.InstanceName) i.Hostname = a.assign(metadata.Hostname) i.Project = a.assign(metadata.ProjectID) i.InternalIP = a.assign(metadata.InternalIP) i.ExternalIP = a.assign(metadata.ExternalIP) if a.err != nil { i.Error = a.err.Error() } return i }
// NewServiceClient returns a Client for use when running on Google // Compute Engine. This client can access buckets owned by the same // project ID as the VM. func NewServiceClient() (*Client, error) { if !metadata.OnGCE() { return nil, errors.New("not running on Google Compute Engine") } scopes, _ := metadata.Scopes("default") haveScope := func(scope string) bool { for _, x := range scopes { if x == scope { return true } } return false } if !haveScope("https://www.googleapis.com/auth/devstorage.full_control") && !haveScope("https://www.googleapis.com/auth/devstorage.read_write") { return nil, errors.New("when this Google Compute Engine VM instance was created, it wasn't granted access to Cloud Storage") } client := oauth2.NewClient(context.Background(), google.ComputeTokenSource("")) service, _ := api.New(client) return &Client{client: client, service: service}, nil }
func GCS(projectid string) cloudstorage.GoogleOAuthClient { onGce := metadata.OnGCE() gcsctx := &cloudstorage.CloudStoreContext{ LogggingContext: "secure-config", TokenSource: cloudstorage.GCEDefaultOAuthToken, Project: projectid, Bucket: "neh", } if onGce { gcsctx.TokenSource = cloudstorage.GCEMetaKeySource } // Create http client with Google context auth googleClient, err := cloudstorage.NewGoogleClient(gcsctx) if err != nil { log.Errorf("failed to create google storage Client: %v", err) os.Exit(1) } return googleClient }