diff --git a/cadvisor.go b/cadvisor.go index ca5dd1de..02b1ea69 100644 --- a/cadvisor.go +++ b/cadvisor.go @@ -15,6 +15,7 @@ package main import ( + "crypto/tls" "flag" "fmt" "net/http" @@ -29,12 +30,14 @@ import ( "github.com/google/cadvisor/container" cadvisorhttp "github.com/google/cadvisor/http" "github.com/google/cadvisor/manager" + "github.com/google/cadvisor/metrics" "github.com/google/cadvisor/utils/sysfs" "github.com/google/cadvisor/version" - "crypto/tls" - - "github.com/google/cadvisor/metrics" + // Register CloudProviders + _ "github.com/google/cadvisor/utils/cloudinfo/aws" + _ "github.com/google/cadvisor/utils/cloudinfo/azure" + _ "github.com/google/cadvisor/utils/cloudinfo/gce" "k8s.io/klog" ) @@ -147,7 +150,7 @@ func main() { collectorHttpClient := createCollectorHttpClient(*collectorCert, *collectorKey) - containerManager, err := manager.New(memoryStorage, sysFs, *maxHousekeepingInterval, *allowDynamicHousekeeping, includedMetrics, &collectorHttpClient, strings.Split(*rawCgroupPrefixWhiteList,",")) + containerManager, err := manager.New(memoryStorage, sysFs, *maxHousekeepingInterval, *allowDynamicHousekeeping, includedMetrics, &collectorHttpClient, strings.Split(*rawCgroupPrefixWhiteList, ",")) if err != nil { klog.Fatalf("Failed to create a Container Manager: %s", err) } diff --git a/utils/cloudinfo/aws.go b/utils/cloudinfo/aws/aws.go similarity index 61% rename from utils/cloudinfo/aws.go rename to utils/cloudinfo/aws/aws.go index f3cdfb31..3b699516 100644 --- a/utils/cloudinfo/aws.go +++ b/utils/cloudinfo/aws/aws.go @@ -15,40 +15,50 @@ package cloudinfo import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/ec2metadata" - "github.com/aws/aws-sdk-go/aws/session" "io/ioutil" "os" "strings" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/ec2metadata" + "github.com/aws/aws-sdk-go/aws/session" + info "github.com/google/cadvisor/info/v1" + "github.com/google/cadvisor/utils/cloudinfo" ) const ( - ProductVerFileName = "/sys/class/dmi/id/product_version" - BiosVerFileName = "/sys/class/dmi/id/bios_vendor" - Amazon = "amazon" + productVerFileName = "/sys/class/dmi/id/product_version" + biosVerFileName = "/sys/class/dmi/id/bios_vendor" + amazon = "amazon" ) -func onAWS() bool { +func init() { + cloudinfo.RegisterCloudProvider(info.AWS, &provider{}) +} + +type provider struct{} + +var _ cloudinfo.CloudProvider = provider{} + +func (provider) IsActiveProvider() bool { var dataProduct []byte var dataBios []byte - if _, err := os.Stat(ProductVerFileName); err == nil { - dataProduct, err = ioutil.ReadFile(ProductVerFileName) + if _, err := os.Stat(productVerFileName); err == nil { + dataProduct, err = ioutil.ReadFile(productVerFileName) if err != nil { return false } } - if _, err := os.Stat(BiosVerFileName); err == nil { - dataBios, err = ioutil.ReadFile(BiosVerFileName) + if _, err := os.Stat(biosVerFileName); err == nil { + dataBios, err = ioutil.ReadFile(biosVerFileName) if err != nil { return false } } - return strings.Contains(string(dataProduct), Amazon) || strings.Contains(strings.ToLower(string(dataBios)), Amazon) + return strings.Contains(string(dataProduct), amazon) || strings.Contains(strings.ToLower(string(dataBios)), amazon) } func getAwsMetadata(name string) string { @@ -60,10 +70,10 @@ func getAwsMetadata(name string) string { return data } -func getAwsInstanceType() info.InstanceType { +func (provider) GetInstanceType() info.InstanceType { return info.InstanceType(getAwsMetadata("instance-type")) } -func getAwsInstanceID() info.InstanceID { +func (provider) GetInstanceID() info.InstanceID { return info.InstanceID(getAwsMetadata("instance-id")) } diff --git a/utils/cloudinfo/azure.go b/utils/cloudinfo/azure/azure.go similarity index 58% rename from utils/cloudinfo/azure.go rename to utils/cloudinfo/azure/azure.go index 2581d63d..d04b0e2b 100644 --- a/utils/cloudinfo/azure.go +++ b/utils/cloudinfo/azure/azure.go @@ -15,32 +15,42 @@ package cloudinfo import ( - info "github.com/google/cadvisor/info/v1" "io/ioutil" "strings" + + info "github.com/google/cadvisor/info/v1" + "github.com/google/cadvisor/utils/cloudinfo" ) const ( - SysVendorFileName = "/sys/class/dmi/id/sys_vendor" - BiosUUIDFileName = "/sys/class/dmi/id/product_uuid" - MicrosoftCorporation = "Microsoft Corporation" + sysVendorFileName = "/sys/class/dmi/id/sys_vendor" + biosUUIDFileName = "/sys/class/dmi/id/product_uuid" + microsoftCorporation = "Microsoft Corporation" ) -func onAzure() bool { - data, err := ioutil.ReadFile(SysVendorFileName) +func init() { + cloudinfo.RegisterCloudProvider(info.Azure, &provider{}) +} + +type provider struct{} + +var _ cloudinfo.CloudProvider = provider{} + +func (provider) IsActiveProvider() bool { + data, err := ioutil.ReadFile(sysVendorFileName) if err != nil { return false } - return strings.Contains(string(data), MicrosoftCorporation) + return strings.Contains(string(data), microsoftCorporation) } // TODO: Implement method. -func getAzureInstanceType() info.InstanceType { +func (provider) GetInstanceType() info.InstanceType { return info.UnknownInstance } -func getAzureInstanceID() info.InstanceID { - data, err := ioutil.ReadFile(BiosUUIDFileName) +func (provider) GetInstanceID() info.InstanceID { + data, err := ioutil.ReadFile(biosUUIDFileName) if err != nil { return info.UnNamedInstance } diff --git a/utils/cloudinfo/cloudinfo.go b/utils/cloudinfo/cloudinfo.go index 22cf6f6b..6325d44b 100644 --- a/utils/cloudinfo/cloudinfo.go +++ b/utils/cloudinfo/cloudinfo.go @@ -18,6 +18,7 @@ package cloudinfo import ( info "github.com/google/cadvisor/info/v1" + "k8s.io/klog" ) type CloudInfo interface { @@ -26,6 +27,29 @@ type CloudInfo interface { GetInstanceID() info.InstanceID } +// CloudProvider is an abstraction for providing cloud-specific information. +type CloudProvider interface { + // IsActiveProvider determines whether this is the cloud provider operating + // this instance. + IsActiveProvider() bool + // GetInstanceType gets the type of instance this process is running on. + // The behavior is undefined if this is not the active provider. + GetInstanceType() info.InstanceType + // GetInstanceType gets the ID of the instance this process is running on. + // The behavior is undefined if this is not the active provider. + GetInstanceID() info.InstanceID +} + +var providers = map[info.CloudProvider]CloudProvider{} + +// RegisterCloudProvider registers the given cloud provider +func RegisterCloudProvider(name info.CloudProvider, provider CloudProvider) { + if _, alreadyRegistered := providers[name]; alreadyRegistered { + klog.Warningf("Duplicate registration of CloudProvider %s", name) + } + providers[name] = provider +} + type realCloudInfo struct { cloudProvider info.CloudProvider instanceType info.InstanceType @@ -33,13 +57,21 @@ type realCloudInfo struct { } func NewRealCloudInfo() CloudInfo { - cloudProvider := detectCloudProvider() - instanceType := detectInstanceType(cloudProvider) - instanceID := detectInstanceID(cloudProvider) + for name, provider := range providers { + if provider.IsActiveProvider() { + return &realCloudInfo{ + cloudProvider: name, + instanceType: provider.GetInstanceType(), + instanceID: provider.GetInstanceID(), + } + } + } + + // No registered active provider. return &realCloudInfo{ - cloudProvider: cloudProvider, - instanceType: instanceType, - instanceID: instanceID, + cloudProvider: info.UnknownProvider, + instanceType: info.UnknownInstance, + instanceID: info.UnNamedInstance, } } @@ -54,50 +86,3 @@ func (self *realCloudInfo) GetInstanceType() info.InstanceType { func (self *realCloudInfo) GetInstanceID() info.InstanceID { return self.instanceID } - -func detectCloudProvider() info.CloudProvider { - switch { - case onGCE(): - return info.GCE - case onAWS(): - return info.AWS - case onAzure(): - return info.Azure - case onBaremetal(): - return info.Baremetal - } - return info.UnknownProvider -} - -func detectInstanceType(cloudProvider info.CloudProvider) info.InstanceType { - switch cloudProvider { - case info.GCE: - return getGceInstanceType() - case info.AWS: - return getAwsInstanceType() - case info.Azure: - return getAzureInstanceType() - case info.Baremetal: - return info.NoInstance - } - return info.UnknownInstance -} - -func detectInstanceID(cloudProvider info.CloudProvider) info.InstanceID { - switch cloudProvider { - case info.GCE: - return getGceInstanceID() - case info.AWS: - return getAwsInstanceID() - case info.Azure: - return getAzureInstanceID() - case info.Baremetal: - return info.UnNamedInstance - } - return info.UnNamedInstance -} - -// TODO: Implement method. -func onBaremetal() bool { - return false -} diff --git a/utils/cloudinfo/gce.go b/utils/cloudinfo/gce/gce.go similarity index 80% rename from utils/cloudinfo/gce.go rename to utils/cloudinfo/gce/gce.go index 7e4856a4..f4111c7a 100644 --- a/utils/cloudinfo/gce.go +++ b/utils/cloudinfo/gce/gce.go @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cloudinfo +package gce import ( "io/ioutil" "strings" info "github.com/google/cadvisor/info/v1" + "github.com/google/cadvisor/utils/cloudinfo" "cloud.google.com/go/compute/metadata" "k8s.io/klog" @@ -29,7 +30,15 @@ const ( google = "Google" ) -func onGCE() bool { +func init() { + cloudinfo.RegisterCloudProvider(info.GCE, &provider{}) +} + +type provider struct{} + +var _ cloudinfo.CloudProvider = provider{} + +func (provider) IsActiveProvider() bool { data, err := ioutil.ReadFile(gceProductName) if err != nil { klog.V(2).Infof("Error while reading product_name: %v", err) @@ -38,7 +47,7 @@ func onGCE() bool { return strings.Contains(string(data), google) } -func getGceInstanceType() info.InstanceType { +func (provider) GetInstanceType() info.InstanceType { machineType, err := metadata.Get("instance/machine-type") if err != nil { return info.UnknownInstance @@ -48,7 +57,7 @@ func getGceInstanceType() info.InstanceType { return info.InstanceType(responseParts[len(responseParts)-1]) } -func getGceInstanceID() info.InstanceID { +func (provider) GetInstanceID() info.InstanceID { instanceID, err := metadata.Get("instance/id") if err != nil { return info.UnknownInstance