NAP interface implementation - part 1

This commit is contained in:
Marcin Wielgus 2017-08-24 16:19:00 +02:00
parent 21c575f0ac
commit ac2c471eb1
8 changed files with 93 additions and 45 deletions

View File

@ -213,6 +213,11 @@ func (asg *Asg) Create() error {
return cloudprovider.ErrAlreadyExist return cloudprovider.ErrAlreadyExist
} }
// Autoprovisioned returns true if the node group is autoprovisioned.
func (asg *Asg) Autoprovisioned() bool {
return false
}
// Delete deletes the node group on the cloud provider side. // Delete deletes the node group on the cloud provider side.
// This will be executed only for autoprovisioned node groups, once their size drops to 0. // This will be executed only for autoprovisioned node groups, once their size drops to 0.
func (asg *Asg) Delete() error { func (asg *Asg) Delete() error {

View File

@ -119,6 +119,10 @@ type NodeGroup interface {
// This will be executed only for autoprovisioned node groups, once their size drops to 0. // This will be executed only for autoprovisioned node groups, once their size drops to 0.
// Implementation optional. // Implementation optional.
Delete() error Delete() error
// Autoprovisioned returns true if the node group is autoprovisioned. An autoprovisioned group
// was created by CA and can be deleted when scaled to 0.
Autoprovisioned() bool
} }
// PricingModel contains information about the node price and how it changes in time. // PricingModel contains information about the node price and how it changes in time.

View File

@ -28,6 +28,11 @@ import (
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache" "k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
) )
const (
maxAutoprovisionedSize = 1000
minAutoprovisionedSize = 0
)
// GceCloudProvider implements CloudProvider interface. // GceCloudProvider implements CloudProvider interface.
type GceCloudProvider struct { type GceCloudProvider struct {
gceManager *GceManager gceManager *GceManager
@ -131,6 +136,7 @@ type Mig struct {
minSize int minSize int
maxSize int maxSize int
autoprovisioned bool
} }
// MaxSize returns maximum size of the node group. // MaxSize returns maximum size of the node group.
@ -266,6 +272,11 @@ func (mig *Mig) Delete() error {
return cloudprovider.ErrNotImplemented return cloudprovider.ErrNotImplemented
} }
// Autoprovisioned returns true if the node group is autoprovisioned.
func (mig *Mig) Autoprovisioned() bool {
return mig.autoprovisioned
}
// TemplateNodeInfo returns a node template for this node group. // TemplateNodeInfo returns a node template for this node group.
func (mig *Mig) TemplateNodeInfo() (*schedulercache.NodeInfo, error) { func (mig *Mig) TemplateNodeInfo() (*schedulercache.NodeInfo, error) {
template, err := mig.gceManager.getMigTemplate(mig) template, err := mig.gceManager.getMigTemplate(mig)

View File

@ -39,6 +39,8 @@ import (
apiv1 "k8s.io/api/core/v1" apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"cloud.google.com/go/compute/metadata"
provider_gce "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" provider_gce "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
) )
@ -59,6 +61,8 @@ type GceManager struct {
service *gce.Service service *gce.Service
cacheMutex sync.Mutex cacheMutex sync.Mutex
zone string
projectId string
} }
// CreateGceManager constructs gceManager object. // CreateGceManager constructs gceManager object.
@ -80,6 +84,11 @@ func CreateGceManager(configReader io.Reader) (*GceManager, error) {
} else { } else {
glog.Infof("Using default TokenSource %#v", tokenSource) glog.Infof("Using default TokenSource %#v", tokenSource)
} }
projectId, zone, err := getProjectAndZone()
if err != nil {
return nil, err
}
glog.V(1).Infof("GCE projectId=%s zone=%s", projectId, zone)
// Create Google Compute Engine service. // Create Google Compute Engine service.
client := oauth2.NewClient(oauth2.NoContext, tokenSource) client := oauth2.NewClient(oauth2.NoContext, tokenSource)
@ -91,6 +100,8 @@ func CreateGceManager(configReader io.Reader) (*GceManager, error) {
migs: make([]*migInformation, 0), migs: make([]*migInformation, 0),
service: gceService, service: gceService,
migCache: make(map[GceRef]*Mig), migCache: make(map[GceRef]*Mig),
zone: zone,
projectId: projectId,
} }
go wait.Forever(func() { go wait.Forever(func() {
manager.cacheMutex.Lock() manager.cacheMutex.Lock()
@ -286,6 +297,17 @@ func (m *GceManager) getMigTemplate(mig *Mig) (*gce.InstanceTemplate, error) {
return instanceTemplate, nil return instanceTemplate, nil
} }
func (m *GceManager) getCpuAndMemoryForMachineType(machineType string) (cpu int64, mem int64, err error) {
if strings.HasPrefix(machineType, "custom-") {
return parseCustomMachineType(machineType)
}
machine, geterr := m.service.MachineTypes.Get(m.projectId, m.zone, machineType).Do()
if geterr != nil {
return 0, 0, geterr
}
return machine.GuestCpus, machine.MemoryMb * 1024 * 1024, nil
}
func (m *GceManager) buildNodeFromTemplate(mig *Mig, template *gce.InstanceTemplate) (*apiv1.Node, error) { func (m *GceManager) buildNodeFromTemplate(mig *Mig, template *gce.InstanceTemplate) (*apiv1.Node, error) {
if template.Properties == nil { if template.Properties == nil {
@ -304,25 +326,16 @@ func (m *GceManager) buildNodeFromTemplate(mig *Mig, template *gce.InstanceTempl
Capacity: apiv1.ResourceList{}, Capacity: apiv1.ResourceList{},
} }
// TODO: get a real value. // TODO: get a real value.
// TODO: handle GPU
node.Status.Capacity[apiv1.ResourcePods] = *resource.NewQuantity(110, resource.DecimalSI) node.Status.Capacity[apiv1.ResourcePods] = *resource.NewQuantity(110, resource.DecimalSI)
// TODO: handle custom !!!! cpu, mem, err := m.getCpuAndMemoryForMachineType(template.Properties.MachineType)
// TODO: handle GPU
if strings.HasPrefix(template.Properties.MachineType, "custom-") {
cpu, mem, err := parseCustomMachineType(template.Properties.MachineType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
node.Status.Capacity[apiv1.ResourceCPU] = *resource.NewQuantity(cpu, resource.DecimalSI) node.Status.Capacity[apiv1.ResourceCPU] = *resource.NewQuantity(cpu, resource.DecimalSI)
node.Status.Capacity[apiv1.ResourceMemory] = *resource.NewQuantity(mem, resource.DecimalSI) node.Status.Capacity[apiv1.ResourceMemory] = *resource.NewQuantity(mem, resource.DecimalSI)
} else {
machineType, err := m.service.MachineTypes.Get(mig.Project, mig.Zone, template.Properties.MachineType).Do()
if err != nil {
return nil, err
}
node.Status.Capacity[apiv1.ResourceCPU] = *resource.NewQuantity(machineType.GuestCpus, resource.DecimalSI)
node.Status.Capacity[apiv1.ResourceMemory] = *resource.NewQuantity(machineType.MemoryMb*1024*1024, resource.DecimalSI)
}
// TODO: use proper allocatable!! // TODO: use proper allocatable!!
node.Status.Allocatable = node.Status.Capacity node.Status.Allocatable = node.Status.Capacity
@ -450,3 +463,21 @@ func buildTaints(kubeEnvTaints map[string]string) ([]apiv1.Taint, error) {
} }
return taints, nil return taints, nil
} }
// Code borrowed from gce cloud provider. Reuse the original as soon as it becomes public.
func getProjectAndZone() (string, string, error) {
result, err := metadata.Get("instance/zone")
if err != nil {
return "", "", err
}
parts := strings.Split(result, "/")
if len(parts) != 4 {
return "", "", fmt.Errorf("unexpected response: %s", result)
}
zone := parts[3]
projectID, err := metadata.ProjectID()
if err != nil {
return "", "", err
}
return projectID, zone, nil
}

View File

@ -239,6 +239,11 @@ func (nodeGroup *NodeGroup) Delete() error {
return cloudprovider.ErrNotImplemented return cloudprovider.ErrNotImplemented
} }
// Autoprovisioned returns true if the node group is autoprovisioned.
func (nodeGroup *NodeGroup) Autoprovisioned() bool {
return false
}
func buildNodeGroup(value string, kubemarkController *kubemark.KubemarkController) (*NodeGroup, error) { func buildNodeGroup(value string, kubemarkController *kubemark.KubemarkController) (*NodeGroup, error) {
spec, err := dynamic.SpecFromString(value, true) spec, err := dynamic.SpecFromString(value, true)
if err != nil { if err != nil {

View File

@ -25,19 +25,23 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider" "k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/utils/errors" "k8s.io/autoscaler/cluster-autoscaler/utils/errors"
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache" )
const (
// ProviderName is the cloud provider name for kubemark
ProviderName = "kubemark"
) )
type KubemarkCloudProvider struct{} type KubemarkCloudProvider struct{}
func BuildKubemarkCloudProvider(kubemarkController *kubemark.KubemarkController, specs []string) (*KubemarkCloudProvider, error) { func BuildKubemarkCloudProvider(kubemarkController interface{}, specs []string) (*KubemarkCloudProvider, error) {
return nil, cloudprovider.ErrNotImplemented return nil, cloudprovider.ErrNotImplemented
} }
func (kubemark *KubemarkCloudProvider) Name() string { return "" } func (kubemark *KubemarkCloudProvider) Name() string { return "" }
func (kubemark *KubemarkCloudProvider) NodeGroups() []cloudprovider.NodeGroup { func (kubemark *KubemarkCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
return []cloudProvider.NodeGroup{} return []cloudprovider.NodeGroup{}
} }
func (kubemark *KubemarkCloudProvider) Pricing() (cloudprovider.PricingModel, errors.AutoscalerError) { func (kubemark *KubemarkCloudProvider) Pricing() (cloudprovider.PricingModel, errors.AutoscalerError) {
@ -55,21 +59,3 @@ func (kubemark *KubemarkCloudProvider) GetAvilableMachineTypes() ([]string, erro
func (kubemark *KubemarkCloudProvider) NewNodeGroup(name string, machineType string, labels map[string]string, extraResources map[string]resource.Quantity) (cloudprovider.NodeGroup, error) { func (kubemark *KubemarkCloudProvider) NewNodeGroup(name string, machineType string, labels map[string]string, extraResources map[string]resource.Quantity) (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrNotImplemented return nil, cloudprovider.ErrNotImplemented
} }
type FakeNodeGroup struct{}
func (f *FakeNodeGroup) Id() string { return "" }
func (f *FakeNodeGroup) MinSize() int { return 0 }
func (f *FakeNodeGroup) MaxSize() int { return 0 }
func (f *FakeNodeGroup) Debug() string { return "" }
func (f *FakeNodeGroup) Nodes() ([]string, error) { return []string{}, cloudprovider.ErrNotImplemented }
func (f *FakeNodeGroup) DeleteNodes(nodes []*apiv1.Node) error { return cloudprovider.ErrNotImplemented }
func (f *FakeNodeGroup) IncreaseSize(delta int) error { return cloudprovider.ErrNotImplemented }
func (f *FakeNodeGroup) TargetSize() (int, error) { return 0, cloudprovider.ErrNotImplemented }
func (f *FakeNodeGroup) DecreaseTargetSize(delta int) error { return cloudprovider.ErrNotImplemented }
func (f *FakeNodeGroup) TemplateNodeInfo() (*schedulercache.NodeInfo, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (f *FakeNodeGroup) Exist() (bool, error) { return true, nil }
func (f *FakeNodeGroup) Create() error { return cloudprovider.ErrNotImplemented }
func (f *FakeNodeGroup) Delete() error { return cloudprovider.ErrNotImplemented }

View File

@ -248,6 +248,11 @@ func (tng *TestNodeGroup) Nodes() ([]string, error) {
return result, nil return result, nil
} }
// Autoprovisioned returns true if the node group is autoprovisioned.
func (tng *TestNodeGroup) Autoprovisioned() bool {
return false
}
// TemplateNodeInfo returns a node template for this node group. // TemplateNodeInfo returns a node template for this node group.
func (tng *TestNodeGroup) TemplateNodeInfo() (*schedulercache.NodeInfo, error) { func (tng *TestNodeGroup) TemplateNodeInfo() (*schedulercache.NodeInfo, error) {
return nil, cloudprovider.ErrNotImplemented return nil, cloudprovider.ErrNotImplemented

View File

@ -49,6 +49,7 @@ func (f *FakeNodeGroup) TemplateNodeInfo() (*schedulercache.NodeInfo, error) {
func (f *FakeNodeGroup) Exist() (bool, error) { return true, nil } func (f *FakeNodeGroup) Exist() (bool, error) { return true, nil }
func (f *FakeNodeGroup) Create() error { return cloudprovider.ErrAlreadyExist } func (f *FakeNodeGroup) Create() error { return cloudprovider.ErrAlreadyExist }
func (f *FakeNodeGroup) Delete() error { return cloudprovider.ErrNotImplemented } func (f *FakeNodeGroup) Delete() error { return cloudprovider.ErrNotImplemented }
func (f *FakeNodeGroup) Autoprovisioned() bool { return false }
func makeNodeInfo(cpu int64, memory int64, pods int64) *schedulercache.NodeInfo { func makeNodeInfo(cpu int64, memory int64, pods int64) *schedulercache.NodeInfo {
node := &apiv1.Node{ node := &apiv1.Node{