github.com/waldiirawan/apm-agent-go/v2@v2.2.2/internal/apmcloudutil/provider.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // 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, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package apmcloudutil 19 20 import ( 21 "context" 22 "fmt" 23 "net" 24 "net/http" 25 "time" 26 27 "github.com/waldiirawan/apm-agent-go/v2/model" 28 ) 29 30 // defaultClient is essentially the same as http.DefaultTransport, except 31 // that it has a short (100ms) dial timeout to avoid delaying startup. 32 var defaultClient = &http.Client{ 33 Transport: &http.Transport{ 34 Proxy: http.ProxyFromEnvironment, 35 DialContext: (&net.Dialer{ 36 Timeout: 100 * time.Millisecond, 37 KeepAlive: 30 * time.Second, 38 DualStack: true, 39 }).DialContext, 40 MaxIdleConns: 100, 41 }, 42 } 43 44 // Provider identifies the cloud provider. 45 type Provider string 46 47 const ( 48 // None is a pseudo cloud provider which disables fetching of 49 // cloud metadata. 50 None Provider = "none" 51 52 // Auto is a pseudo cloud provider which uses trial-and-error to 53 // fetch cloud metadata from all supported clouds. 54 Auto Provider = "auto" 55 56 // AWS represents the Amazon Web Services (EC2) cloud provider. 57 AWS Provider = "aws" 58 59 // Azure represents the Microsoft Azure cloud provider. 60 Azure Provider = "azure" 61 62 // GCP represents the Google Cloud Platform cloud provider. 63 GCP Provider = "gcp" 64 ) 65 66 // ParseProvider parses the provider name "s", returning the relevant Provider. 67 // 68 // If the provider name is unknown, None will be returned with an error. 69 func ParseProvider(s string) (Provider, error) { 70 switch Provider(s) { 71 case Auto, AWS, Azure, GCP, None: 72 return Provider(s), nil 73 } 74 return None, fmt.Errorf("unknown cloud provider %q", s) 75 } 76 77 // GetCloudMetadata attempts to fetch cloud metadata for cloud provider p, 78 // storing it into out and returning a boolean indicating that the metadata 79 // was successfully retrieved. 80 // 81 // It is the caller's responsibility to set a reasonable timeout, to ensure 82 // requests do not block normal operation in non-cloud environments. 83 func (p Provider) GetCloudMetadata(ctx context.Context, logger Logger, out *model.Cloud) bool { 84 return p.getCloudMetadata(ctx, defaultClient, logger, out) 85 } 86 87 func (p Provider) getCloudMetadata(ctx context.Context, client *http.Client, logger Logger, out *model.Cloud) bool { 88 if p == None { 89 return false 90 } 91 // Rather than switching on p, we loop through all providers 92 // to support "auto". If and only if p == Auto, we'll loop back 93 // around on errors. 94 for _, provider := range []Provider{AWS, Azure, GCP} { 95 if p != Auto && p != provider { 96 continue 97 } 98 var err error 99 switch provider { 100 case AWS: 101 err = getAWSCloudMetadata(ctx, client, out) 102 case Azure: 103 err = getAzureCloudMetadata(ctx, client, out) 104 case GCP: 105 err = getGCPCloudMetadata(ctx, client, out) 106 } 107 if err == nil { 108 out.Provider = string(provider) 109 return true 110 } else if p != Auto { 111 if logger != nil { 112 logger.Warningf("cloud provider %q specified, but cloud metadata could not be retrieved: %s", p, err) 113 } 114 return false 115 } 116 } 117 return false 118 } 119 120 // Logger defines the interface for logging while fetching cloud metadata. 121 type Logger interface { 122 Warningf(format string, args ...interface{}) 123 }