mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Add support for oVirt cloud provider
This patch adds the initial support for the oVirt cloud provider. Signed-off-by: Federico Simoncelli <fsimonce@redhat.com>
This commit is contained in:
		
							
								
								
									
										9
									
								
								cluster/ovirt/ovirt-cloud.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								cluster/ovirt/ovirt-cloud.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
# ovirt-cloud.conf
 | 
			
		||||
[connection]
 | 
			
		||||
uri = https://localhost:8443/ovirt-engine/api
 | 
			
		||||
username = admin@internal
 | 
			
		||||
password = admin
 | 
			
		||||
 | 
			
		||||
[filters]
 | 
			
		||||
# Search queries used to find minions
 | 
			
		||||
vms = tag=kubernetes
 | 
			
		||||
@@ -22,4 +22,5 @@ package main
 | 
			
		||||
import (
 | 
			
		||||
	_ "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/gce"
 | 
			
		||||
	_ "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/vagrant"
 | 
			
		||||
	_ "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/ovirt"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										156
									
								
								pkg/cloudprovider/ovirt/ovirt.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								pkg/cloudprovider/ovirt/ovirt.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
			
		||||
/*
 | 
			
		||||
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 ovirt_cloud
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.google.com/p/gcfg"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type OVirtCloud struct {
 | 
			
		||||
	VmsRequest         *url.URL
 | 
			
		||||
	HostsRequest       *url.URL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type OVirtApiConfig struct {
 | 
			
		||||
	Connection struct {
 | 
			
		||||
		ApiEntry string `gcfg:"uri"`
 | 
			
		||||
		Username string `gcfg:"username"`
 | 
			
		||||
		Password string `gcfg:"password"`
 | 
			
		||||
	}
 | 
			
		||||
	Filters struct {
 | 
			
		||||
		VmsQuery   string `gcfg:"vms"`
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type XmlVmInfo struct {
 | 
			
		||||
	Hostname        string `xml:"guest_info>fqdn"`
 | 
			
		||||
	State		string `xml:"status>state"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type XmlVmsList struct {
 | 
			
		||||
	XMLName         xml.Name     `xml:"vms"`
 | 
			
		||||
	Vm		[]XmlVmInfo  `xml:"vm"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	cloudprovider.RegisterCloudProvider("ovirt",
 | 
			
		||||
		func(config io.Reader) (cloudprovider.Interface, error) {
 | 
			
		||||
			return newOVirtCloud(config)
 | 
			
		||||
		})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newOVirtCloud(config io.Reader) (*OVirtCloud, error) {
 | 
			
		||||
	if config == nil {
 | 
			
		||||
		return nil, fmt.Errorf("missing configuration file for ovirt cloud provider")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	oVirtConfig := OVirtApiConfig{}
 | 
			
		||||
 | 
			
		||||
	/* defaults */
 | 
			
		||||
	oVirtConfig.Connection.Username = "admin@internal"
 | 
			
		||||
 | 
			
		||||
	if  err := gcfg.ReadInto(&oVirtConfig, config); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if oVirtConfig.Connection.ApiEntry == "" {
 | 
			
		||||
		return nil, fmt.Errorf("missing ovirt uri in cloud provider configuration")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	request, err := url.Parse(oVirtConfig.Connection.ApiEntry)
 | 
			
		||||
	if  err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	request.Path = path.Join(request.Path, "vms")
 | 
			
		||||
	request.User = url.UserPassword(oVirtConfig.Connection.Username, oVirtConfig.Connection.Password)
 | 
			
		||||
	request.RawQuery = url.Values{"search": {oVirtConfig.Filters.VmsQuery}}.Encode()
 | 
			
		||||
 | 
			
		||||
	return &OVirtCloud{VmsRequest: request}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TCPLoadBalancer returns an implementation of TCPLoadBalancer for oVirt cloud
 | 
			
		||||
func (v *OVirtCloud) TCPLoadBalancer() (cloudprovider.TCPLoadBalancer, bool) {
 | 
			
		||||
	return nil, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Instances returns an implementation of Instances for oVirt cloud
 | 
			
		||||
func (v *OVirtCloud) Instances() (cloudprovider.Instances, bool) {
 | 
			
		||||
	return v, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Zones returns an implementation of Zones for oVirt cloud
 | 
			
		||||
func (v *OVirtCloud) Zones() (cloudprovider.Zones, bool) {
 | 
			
		||||
	return nil, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IPAddress returns the address of a particular machine instance
 | 
			
		||||
func (v *OVirtCloud) IPAddress(instance string) (net.IP, error) {
 | 
			
		||||
	// since the instance now is the IP in the ovirt env, this is trivial no-op
 | 
			
		||||
	return net.ParseIP(instance), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getInstancesFromXml(body io.Reader) ([]string, error) {
 | 
			
		||||
	if body == nil {
 | 
			
		||||
		return nil, fmt.Errorf("ovirt rest-api response body is missing")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	content, err := ioutil.ReadAll(body)
 | 
			
		||||
	if  err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vmlist := XmlVmsList{}
 | 
			
		||||
 | 
			
		||||
	if err := xml.Unmarshal(content, &vmlist); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var instances []string
 | 
			
		||||
 | 
			
		||||
	for _, vm := range vmlist.Vm {
 | 
			
		||||
		// Always return only vms that are up and running
 | 
			
		||||
		if vm.Hostname != "" && strings.ToLower(vm.State) == "up" {
 | 
			
		||||
			instances = append(instances, vm.Hostname)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return instances, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// List enumerates the set of minions instances known by the cloud provider
 | 
			
		||||
func (v *OVirtCloud) List(filter string) ([]string, error) {
 | 
			
		||||
	response, err := http.Get(v.VmsRequest.String())
 | 
			
		||||
	if  err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer response.Body.Close()
 | 
			
		||||
 | 
			
		||||
	return getInstancesFromXml(response.Body)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										124
									
								
								pkg/cloudprovider/ovirt/ovirt_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								pkg/cloudprovider/ovirt/ovirt_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
/*
 | 
			
		||||
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 ovirt_cloud
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestOVirtCloudConfiguration(t *testing.T) {
 | 
			
		||||
	config1 := (io.Reader)(nil)
 | 
			
		||||
 | 
			
		||||
	_, err1 := cloudprovider.GetCloudProvider("ovirt", config1)
 | 
			
		||||
	if err1 == nil {
 | 
			
		||||
		t.Fatalf("An error is expected when the configuration is missing")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config2 := strings.NewReader("")
 | 
			
		||||
 | 
			
		||||
	_, err2 := cloudprovider.GetCloudProvider("ovirt", config2)
 | 
			
		||||
	if err2 == nil {
 | 
			
		||||
		t.Fatalf("An error is expected when the configuration is empty")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config3 := strings.NewReader(`
 | 
			
		||||
[connection]
 | 
			
		||||
	`)
 | 
			
		||||
 | 
			
		||||
	_, err3 := cloudprovider.GetCloudProvider("ovirt", config3)
 | 
			
		||||
	if err3 == nil {
 | 
			
		||||
		t.Fatalf("An error is expected when the uri is missing")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config4 := strings.NewReader(`
 | 
			
		||||
[connection]
 | 
			
		||||
uri = https://localhost:8443/ovirt-engine/api
 | 
			
		||||
`)
 | 
			
		||||
 | 
			
		||||
	_, err4 := cloudprovider.GetCloudProvider("ovirt", config4)
 | 
			
		||||
	if err4 != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error creating the provider: %s", err4)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOVirtCloudXmlParsing(t *testing.T) {
 | 
			
		||||
	body1 := (io.Reader)(nil)
 | 
			
		||||
 | 
			
		||||
	_, err1 := getInstancesFromXml(body1)
 | 
			
		||||
	if err1 == nil {
 | 
			
		||||
		t.Fatalf("An error is expected when body is missing")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body2 := strings.NewReader("")
 | 
			
		||||
 | 
			
		||||
	_, err2 := getInstancesFromXml(body2)
 | 
			
		||||
	if err2 == nil {
 | 
			
		||||
		t.Fatalf("An error is expected when body is empty")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body3 := strings.NewReader(`
 | 
			
		||||
<vms>
 | 
			
		||||
  <vm></vm>
 | 
			
		||||
</vms>
 | 
			
		||||
`)
 | 
			
		||||
 | 
			
		||||
	instances3, err3 := getInstancesFromXml(body3)
 | 
			
		||||
	if err3 != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error listing instances: %s", err3)
 | 
			
		||||
	}
 | 
			
		||||
	if len(instances3) > 0 {
 | 
			
		||||
		t.Fatalf("Unexpected number of instance(s): %i", len(instances3))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body4 := strings.NewReader(`
 | 
			
		||||
<vms>
 | 
			
		||||
  <vm>
 | 
			
		||||
    <status><state>Up</state></status>
 | 
			
		||||
    <guest_info><fqdn>host1</fqdn></guest_info>
 | 
			
		||||
  </vm>
 | 
			
		||||
  <vm>
 | 
			
		||||
    <!-- empty -->
 | 
			
		||||
  </vm>
 | 
			
		||||
  <vm>
 | 
			
		||||
    <status><state>Up</state></status>
 | 
			
		||||
  </vm>
 | 
			
		||||
  <vm>
 | 
			
		||||
    <status><state>Down</state></status>
 | 
			
		||||
    <guest_info><fqdn>host2</fqdn></guest_info>
 | 
			
		||||
  </vm>
 | 
			
		||||
  <vm>
 | 
			
		||||
    <status><state>Up</state></status>
 | 
			
		||||
    <guest_info><fqdn>host3</fqdn></guest_info>
 | 
			
		||||
  </vm>
 | 
			
		||||
</vms>
 | 
			
		||||
`)
 | 
			
		||||
 | 
			
		||||
	instances4, err4 := getInstancesFromXml(body4)
 | 
			
		||||
	if err4 != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error listing instances: %s", err4)
 | 
			
		||||
	}
 | 
			
		||||
	if len(instances4) != 2 {
 | 
			
		||||
		t.Fatalf("Unexpected number of instance(s): %i", len(instances4))
 | 
			
		||||
	}
 | 
			
		||||
	if instances4[0] != "host1" || instances4[1] != "host3" {
 | 
			
		||||
		t.Fatalf("Unexpected instance(s): %s", instances4)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user