From f7d54390f9d443571bfc4bb8f95b5751fe93f0f4 Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Tue, 19 Aug 2014 16:40:47 -0700 Subject: [PATCH] Make cloud providers be plugins --- cmd/apiserver/apiserver.go | 24 +++--------- cmd/apiserver/plugins.go | 25 +++++++++++++ pkg/cloudprovider/gce/gce.go | 8 +++- pkg/cloudprovider/plugins.go | 56 ++++++++++++++++++++++++++++ pkg/cloudprovider/vagrant/vagrant.go | 8 +++- 5 files changed, 99 insertions(+), 22 deletions(-) create mode 100644 cmd/apiserver/plugins.go create mode 100644 pkg/cloudprovider/plugins.go diff --git a/cmd/apiserver/apiserver.go b/cmd/apiserver/apiserver.go index 5c0b13beb1..5fb6792624 100644 --- a/cmd/apiserver/apiserver.go +++ b/cmd/apiserver/apiserver.go @@ -28,8 +28,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" - "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/gce" - "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/vagrant" "github.com/GoogleCloudPlatform/kubernetes/pkg/master" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" verflag "github.com/GoogleCloudPlatform/kubernetes/pkg/version/flag" @@ -77,23 +75,13 @@ func main() { glog.Fatalf("-etcd_servers flag is required.") } - var cloud cloudprovider.Interface - switch *cloudProvider { - case "gce": - var err error - cloud, err = gce_cloud.NewGCECloud() - if err != nil { - glog.Fatalf("Couldn't connect to GCE cloud: %#v", err) - } - case "vagrant": - var err error - cloud, err = vagrant_cloud.NewVagrantCloud() - if err != nil { - glog.Fatalf("Couldn't connect to vagrant cloud: %#v", err) - } - default: + cloud, err := cloudprovider.GetCloudProvider(*cloudProvider) + if err != nil { + glog.Fatalf("Couldn't init cloud provider %q: %#v", *cloudProvider, err) + } + if cloud == nil { if len(*cloudProvider) > 0 { - glog.Infof("Unknown cloud provider: %s", *cloudProvider) + glog.Fatalf("Unknown cloud provider: %s", *cloudProvider) } else { glog.Info("No cloud provider specified.") } diff --git a/cmd/apiserver/plugins.go b/cmd/apiserver/plugins.go new file mode 100644 index 0000000000..9463332c59 --- /dev/null +++ b/cmd/apiserver/plugins.go @@ -0,0 +1,25 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +// This file exists to force the desired plugin implementations to be linked. +// This should probably be part of some configuration fed into the build for a +// given binary target. +import ( + _ "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/gce" + _ "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/vagrant" +) diff --git a/pkg/cloudprovider/gce/gce.go b/pkg/cloudprovider/gce/gce.go index 5777a1ab3c..f8e4c048ea 100644 --- a/pkg/cloudprovider/gce/gce.go +++ b/pkg/cloudprovider/gce/gce.go @@ -39,6 +39,10 @@ type GCECloud struct { instanceRE string } +func init() { + cloudprovider.RegisterCloudProvider("gce", func() (cloudprovider.Interface, error) { return newGCECloud() }) +} + func getProjectAndZone() (string, string, error) { client := http.Client{} url := "http://metadata/computeMetadata/v1/instance/zone" @@ -63,8 +67,8 @@ func getProjectAndZone() (string, string, error) { return parts[1], parts[3], nil } -// NewGCECloud creates a new instance of GCECloud. -func NewGCECloud() (*GCECloud, error) { +// newGCECloud creates a new instance of GCECloud. +func newGCECloud() (*GCECloud, error) { projectID, zone, err := getProjectAndZone() if err != nil { return nil, err diff --git a/pkg/cloudprovider/plugins.go b/pkg/cloudprovider/plugins.go new file mode 100644 index 0000000000..cac60f630e --- /dev/null +++ b/pkg/cloudprovider/plugins.go @@ -0,0 +1,56 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cloudprovider + +import ( + "sync" + + "github.com/golang/glog" +) + +// Factory is a function that returns a cloudprovider.Interface. +type Factory func() (Interface, error) + +// All registered cloud providers. +var providersMutex sync.Mutex +var providers = make(map[string]Factory) + +// RegisterCloudProvider registers a cloudprovider.Factory by name. This +// is expected to happen during app startup. +func RegisterCloudProvider(name string, cloud Factory) { + providersMutex.Lock() + defer providersMutex.Unlock() + _, found := providers[name] + if found { + glog.Fatalf("Cloud provider %q was registered twice", name) + } + glog.Infof("Registered cloud provider %q", name) + providers[name] = cloud +} + +// GetCloudProvider creates an instance of the named cloud provider, or nil if +// the name is not known. The error return is only used if the named provider +// was known but failed to initialize. +func GetCloudProvider(name string) (Interface, error) { + providersMutex.Lock() + defer providersMutex.Unlock() + f, found := providers[name] + if !found { + return nil, nil + } + return f() +} diff --git a/pkg/cloudprovider/vagrant/vagrant.go b/pkg/cloudprovider/vagrant/vagrant.go index 8b4acefbbe..ed79cdcf7a 100644 --- a/pkg/cloudprovider/vagrant/vagrant.go +++ b/pkg/cloudprovider/vagrant/vagrant.go @@ -36,6 +36,10 @@ type VagrantCloud struct { saltAuth string } +func init() { + cloudprovider.RegisterCloudProvider("vagrant", func() (cloudprovider.Interface, error) { return newVagrantCloud() }) +} + // SaltToken is an authorization token required by Salt REST API type SaltToken struct { Token string `json:"token"` @@ -63,8 +67,8 @@ type SaltMinionsResponse struct { Minions []SaltMinions `json:"return"` } -// NewVagrantCloud creates a new instance of VagrantCloud configured to talk to the Salt REST API. -func NewVagrantCloud() (*VagrantCloud, error) { +// newVagrantCloud creates a new instance of VagrantCloud configured to talk to the Salt REST API. +func newVagrantCloud() (*VagrantCloud, error) { return &VagrantCloud{ saltURL: "http://127.0.0.1:8000", saltUser: "vagrant",