Skip to content

Commit

Permalink
Add Cluster Autoscale skeleton (#1)
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre-Emmanuel Jacquier <[email protected]>
  • Loading branch information
pierre-emmanuelJ committed Aug 28, 2020
1 parent d9e8fa3 commit e6d2109
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cluster-autoscaler/cloudprovider/cloud_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const (
BaiducloudProviderName = "baiducloud"
// DigitalOceanProviderName gets the provider name of digitalocean
DigitalOceanProviderName = "digitalocean"
// ExoscaleProviderName gets the provider name of exoscale
ExoscaleProviderName = "exoscale"
// GceProviderName gets the provider name of gce
GceProviderName = "gce"
// MagnumProviderName gets the provider name of magnum
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package exoscale

import (
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
)

var _ cloudprovider.CloudProvider = (*exoscaleCloudProvider)(nil)

const (
exoscaleProviderIDPrefix = "exoscale://"
)

type exoscaleCloudProvider struct {
manager *Manager
resourceLimiter *cloudprovider.ResourceLimiter
}

func newExoscaleCloudProvider(manager *Manager, rl *cloudprovider.ResourceLimiter) (*exoscaleCloudProvider, error) {
if err := manager.Refresh(); err != nil {
return nil, err
}

return &exoscaleCloudProvider{
manager: manager,
resourceLimiter: rl,
}, nil
}

// Name returns name of the cloud provider.
func (e *exoscaleCloudProvider) Name() string {
return ""
}

// NodeGroups returns all node groups configured for this cloud provider.
func (e *exoscaleCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
return nil
}

// NodeGroupForNode returns the node group for the given node, nil if the node
// should not be processed by cluster autoscaler, or non-nil error if such
// occurred. Must be implemented.
func (e *exoscaleCloudProvider) NodeGroupForNode(*apiv1.Node) (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}

// Pricing returns pricing model for this cloud provider or error if not available.
// Implementation optional.
func (e *exoscaleCloudProvider) Pricing() (cloudprovider.PricingModel, errors.AutoscalerError) {
return nil, cloudprovider.ErrNotImplemented
}

// GetAvailableMachineTypes get all machine types that can be requested from the cloud provider.
// Implementation optional.
func (e *exoscaleCloudProvider) GetAvailableMachineTypes() ([]string, error) {
return nil, cloudprovider.ErrNotImplemented
}

// NewNodeGroup builds a theoretical node group based on the node definition provided. The node group is not automatically
// created on the cloud provider side. The node group is not returned by NodeGroups() until it is created.
// Implementation optional.
func (e *exoscaleCloudProvider) NewNodeGroup(machineType string, labels map[string]string, systemLabels map[string]string,
taints []apiv1.Taint, extraResources map[string]resource.Quantity) (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}

// GetResourceLimiter returns struct containing limits (max, min) for resources (cores, memory etc.).
func (e *exoscaleCloudProvider) GetResourceLimiter() (*cloudprovider.ResourceLimiter, error) {
return nil, cloudprovider.ErrNotImplemented
}

// GPULabel returns the label added to nodes with GPU resource.
func (e *exoscaleCloudProvider) GPULabel() string {
return ""
}

// GetAvailableGPUTypes return all available GPU types cloud provider supports.
func (e *exoscaleCloudProvider) GetAvailableGPUTypes() map[string]struct{} {
return nil
}

// Cleanup cleans up open resources before the cloud provider is destroyed, i.e. go routines etc.
func (e *exoscaleCloudProvider) Cleanup() error {
return cloudprovider.ErrNotImplemented
}

// Refresh is called before every main loop and can be used to dynamically update cloud provider state.
// In particular the list of node groups returned by NodeGroups can change as a result of CloudProvider.Refresh().
func (e *exoscaleCloudProvider) Refresh() error {
return cloudprovider.ErrNotImplemented
}
28 changes: 28 additions & 0 deletions cluster-autoscaler/cloudprovider/exoscale/exoscale_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package exoscale

import (
"io"

"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
)

// Manager handles Exoscale communication and data caching of
// node groups (instance pools)
type Manager struct {
clusterID string
nodeGroups []*NodeGroup
}

// Config is the configuration of the Exoscale cloud provider
type Config struct {
}

func newManager(configReader io.Reader) (*Manager, error) {
return nil, cloudprovider.ErrNotImplemented
}

// Refresh refreshes the cache holding the nodegroups. This is called by the CA
// based on the `--scan-interval`. By default it's 10 seconds.
func (m *Manager) Refresh() error {
return cloudprovider.ErrNotImplemented
}
114 changes: 114 additions & 0 deletions cluster-autoscaler/cloudprovider/exoscale/exoscale_node_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package exoscale

import (
"github.com/exoscale/egoscale"
apiv1 "k8s.io/api/core/v1"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"

schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
)

// NodeGroup implements cloudprovider.NodeGroup interface. NodeGroup contains
// configuration info and functions to control a set of nodes that have the
// same capacity and set of labels.
type NodeGroup struct {
id string
clusterID string
nodePool *egoscale.InstancePool

minSize int
maxSize int
}

// MaxSize returns maximum size of the node group.
func (n *NodeGroup) MaxSize() int {
return n.maxSize
}

// MinSize returns minimum size of the node group.
func (n *NodeGroup) MinSize() int {
return n.minSize
}

// TargetSize returns the current target size of the node group. It is possible that the
// number of nodes in Kubernetes is different at the moment but should be equal
// to Size() once everything stabilizes (new nodes finish startup and registration or
// removed nodes are deleted completely). Implementation required.
func (n *NodeGroup) TargetSize() (int, error) {
return 0, cloudprovider.ErrNotImplemented
}

// IncreaseSize increases the size of the node group. To delete a node you need
// to explicitly name it and use DeleteNode. This function should wait until
// node group size is updated. Implementation required.
func (n *NodeGroup) IncreaseSize(delta int) error {
return cloudprovider.ErrNotImplemented
}

// DeleteNodes deletes nodes from this node group. Error is returned either on
// failure or if the given node doesn't belong to this node group. This function
// should wait until node group size is updated. Implementation required.
func (n *NodeGroup) DeleteNodes([]*apiv1.Node) error {
return cloudprovider.ErrNotImplemented
}

// DecreaseTargetSize decreases the target size of the node group. This function
// doesn't permit to delete any existing node and can be used only to reduce the
// request for new nodes that have not been yet fulfilled. Delta should be negative.
// It is assumed that cloud provider will not delete the existing nodes when there
// is an option to just decrease the target. Implementation required.
func (n *NodeGroup) DecreaseTargetSize(delta int) error {
return cloudprovider.ErrNotImplemented
}

// Id returns an unique identifier of the node group.
func (n *NodeGroup) Id() string {
return ""
}

// Debug returns a string containing all information regarding this node group.
func (n *NodeGroup) Debug() string {
return ""
}

// Nodes returns a list of all nodes that belong to this node group.
// It is required that Instance objects returned by this method have Id field set.
// Other fields are optional.
// This list should include also instances that might have not become a kubernetes node yet.
func (n *NodeGroup) Nodes() ([]cloudprovider.Instance, error) {
return nil, cloudprovider.ErrNotImplemented
}

// TemplateNodeInfo returns a schedulerframework.NodeInfo structure of an empty
// (as if just started) node. This will be used in scale-up simulations to
// predict what would a new node look like if a node group was expanded. The returned
// NodeInfo is expected to have a fully populated Node object, with all of the labels,
// capacity and allocatable information as well as all pods that are started on
// the node by default, using manifest (most likely only kube-proxy). Implementation optional.
func (n *NodeGroup) TemplateNodeInfo() (*schedulerframework.NodeInfo, error) {
return nil, cloudprovider.ErrNotImplemented
}

// Exist checks if the node group really exists on the cloud provider side. Allows to tell the
// theoretical node group from the real one. Implementation required.
func (n *NodeGroup) Exist() bool {
return false
}

// Create creates the node group on the cloud provider side. Implementation optional.
func (n *NodeGroup) Create() (cloudprovider.NodeGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}

// 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.
// Implementation optional.
func (n *NodeGroup) Delete() error {
return cloudprovider.ErrNotImplemented
}

// Autoprovisioned returns true if the node group is autoprovisioned. An autoprovisioned group
// was created by CA and can be deleted when scaled to 0.
func (n *NodeGroup) Autoprovisioned() bool {
return false
}

0 comments on commit e6d2109

Please sign in to comment.