mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-30 17:58:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			188 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2015 The Kubernetes Authors.
 | |
| 
 | |
| 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 core
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"net/http"
 | |
| 	"time"
 | |
| 
 | |
| 	utilnet "k8s.io/apimachinery/pkg/util/net"
 | |
| 	restclient "k8s.io/client-go/rest"
 | |
| 	"k8s.io/kubernetes/pkg/api/v1"
 | |
| 	"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
 | |
| 	schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	DefaultExtenderTimeout = 5 * time.Second
 | |
| )
 | |
| 
 | |
| // HTTPExtender implements the algorithm.SchedulerExtender interface.
 | |
| type HTTPExtender struct {
 | |
| 	extenderURL    string
 | |
| 	filterVerb     string
 | |
| 	prioritizeVerb string
 | |
| 	weight         int
 | |
| 	apiVersion     string
 | |
| 	client         *http.Client
 | |
| }
 | |
| 
 | |
| func makeTransport(config *schedulerapi.ExtenderConfig) (http.RoundTripper, error) {
 | |
| 	var cfg restclient.Config
 | |
| 	if config.TLSConfig != nil {
 | |
| 		cfg.TLSClientConfig = *config.TLSConfig
 | |
| 	}
 | |
| 	if config.EnableHttps {
 | |
| 		hasCA := len(cfg.CAFile) > 0 || len(cfg.CAData) > 0
 | |
| 		if !hasCA {
 | |
| 			cfg.Insecure = true
 | |
| 		}
 | |
| 	}
 | |
| 	tlsConfig, err := restclient.TLSConfigFor(&cfg)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if tlsConfig != nil {
 | |
| 		return utilnet.SetTransportDefaults(&http.Transport{
 | |
| 			TLSClientConfig: tlsConfig,
 | |
| 		}), nil
 | |
| 	}
 | |
| 	return utilnet.SetTransportDefaults(&http.Transport{}), nil
 | |
| }
 | |
| 
 | |
| func NewHTTPExtender(config *schedulerapi.ExtenderConfig, apiVersion string) (algorithm.SchedulerExtender, error) {
 | |
| 	if config.HTTPTimeout.Nanoseconds() == 0 {
 | |
| 		config.HTTPTimeout = time.Duration(DefaultExtenderTimeout)
 | |
| 	}
 | |
| 
 | |
| 	transport, err := makeTransport(config)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	client := &http.Client{
 | |
| 		Transport: transport,
 | |
| 		Timeout:   config.HTTPTimeout,
 | |
| 	}
 | |
| 	return &HTTPExtender{
 | |
| 		extenderURL:    config.URLPrefix,
 | |
| 		apiVersion:     apiVersion,
 | |
| 		filterVerb:     config.FilterVerb,
 | |
| 		prioritizeVerb: config.PrioritizeVerb,
 | |
| 		weight:         config.Weight,
 | |
| 		client:         client,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // Filter based on extender implemented predicate functions. The filtered list is
 | |
| // expected to be a subset of the supplied list. failedNodesMap optionally contains
 | |
| // the list of failed nodes and failure reasons.
 | |
| func (h *HTTPExtender) Filter(pod *v1.Pod, nodes []*v1.Node) ([]*v1.Node, schedulerapi.FailedNodesMap, error) {
 | |
| 	var result schedulerapi.ExtenderFilterResult
 | |
| 
 | |
| 	if h.filterVerb == "" {
 | |
| 		return nodes, schedulerapi.FailedNodesMap{}, nil
 | |
| 	}
 | |
| 
 | |
| 	nodeItems := make([]v1.Node, 0, len(nodes))
 | |
| 	for _, node := range nodes {
 | |
| 		nodeItems = append(nodeItems, *node)
 | |
| 	}
 | |
| 	args := schedulerapi.ExtenderArgs{
 | |
| 		Pod:   *pod,
 | |
| 		Nodes: v1.NodeList{Items: nodeItems},
 | |
| 	}
 | |
| 
 | |
| 	if err := h.send(h.filterVerb, &args, &result); err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 	if result.Error != "" {
 | |
| 		return nil, nil, fmt.Errorf(result.Error)
 | |
| 	}
 | |
| 
 | |
| 	nodeResult := make([]*v1.Node, 0, len(result.Nodes.Items))
 | |
| 	for i := range result.Nodes.Items {
 | |
| 		nodeResult = append(nodeResult, &result.Nodes.Items[i])
 | |
| 	}
 | |
| 	return nodeResult, result.FailedNodes, nil
 | |
| }
 | |
| 
 | |
| // Prioritize based on extender implemented priority functions. Weight*priority is added
 | |
| // up for each such priority function. The returned score is added to the score computed
 | |
| // by Kubernetes scheduler. The total score is used to do the host selection.
 | |
| func (h *HTTPExtender) Prioritize(pod *v1.Pod, nodes []*v1.Node) (*schedulerapi.HostPriorityList, int, error) {
 | |
| 	var result schedulerapi.HostPriorityList
 | |
| 
 | |
| 	if h.prioritizeVerb == "" {
 | |
| 		result := schedulerapi.HostPriorityList{}
 | |
| 		for _, node := range nodes {
 | |
| 			result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: 0})
 | |
| 		}
 | |
| 		return &result, 0, nil
 | |
| 	}
 | |
| 
 | |
| 	nodeItems := make([]v1.Node, 0, len(nodes))
 | |
| 	for _, node := range nodes {
 | |
| 		nodeItems = append(nodeItems, *node)
 | |
| 	}
 | |
| 	args := schedulerapi.ExtenderArgs{
 | |
| 		Pod:   *pod,
 | |
| 		Nodes: v1.NodeList{Items: nodeItems},
 | |
| 	}
 | |
| 
 | |
| 	if err := h.send(h.prioritizeVerb, &args, &result); err != nil {
 | |
| 		return nil, 0, err
 | |
| 	}
 | |
| 	return &result, h.weight, nil
 | |
| }
 | |
| 
 | |
| // Helper function to send messages to the extender
 | |
| func (h *HTTPExtender) send(action string, args interface{}, result interface{}) error {
 | |
| 	out, err := json.Marshal(args)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	url := h.extenderURL + "/" + h.apiVersion + "/" + action
 | |
| 
 | |
| 	req, err := http.NewRequest("POST", url, bytes.NewReader(out))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	req.Header.Set("Content-Type", "application/json")
 | |
| 
 | |
| 	resp, err := h.client.Do(req)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	defer resp.Body.Close()
 | |
| 	body, err := ioutil.ReadAll(resp.Body)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if err := json.Unmarshal(body, result); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | 
