Skip to content

Commit 1371175

Browse files
committed
wip: initial commit for qemu-scheduler
1 parent aa1730f commit 1371175

File tree

8 files changed

+109
-39
lines changed

8 files changed

+109
-39
lines changed

cloud/interfaces.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
99

1010
infrav1 "github.com/sp-yduck/cluster-api-provider-proxmox/api/v1beta1"
11+
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/scheduler"
1112
)
1213

1314
type Reconciler interface {
@@ -45,6 +46,7 @@ type ClusterSettter interface {
4546
// MachineGetter is an interface which can get machine information.
4647
type MachineGetter interface {
4748
Client
49+
GetScheduler() *scheduler.Scheduler
4850
Name() string
4951
Namespace() string
5052
// Zone() string

cloud/scheduler/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# qemu-scheduler
2+
3+
Scheduling refers to making sure that VM(QEMU) are matched to Proxmox Nodes.

cloud/scheduler/scheduler.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package scheduler
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"math/rand"
7+
"time"
8+
9+
"github.com/sp-yduck/proxmox-go/api"
10+
"github.com/sp-yduck/proxmox-go/proxmox"
11+
"k8s.io/klog/v2"
12+
"sigs.k8s.io/controller-runtime/pkg/client"
13+
)
14+
15+
var (
16+
// ErrNoNodesAvailable is used to describe the error that no nodes available to schedule qemus.
17+
ErrNoNodesAvailable = fmt.Errorf("no nodes available to schedule qemus")
18+
19+
// ErrNoVMIDAvailable is used to describe the error that no vmid available to schedule qemus.
20+
ErrNoVMIDAvailable = fmt.Errorf("no vmid available to schedule qemus")
21+
)
22+
23+
type Scheduler struct {
24+
k8sClient client.Client
25+
client *proxmox.Service
26+
27+
// logger *must* be initialized when creating a Scheduler,
28+
// otherwise logging functions will access a nil sink and
29+
// panic.
30+
logger klog.Logger
31+
}
32+
33+
type ScheduleResult struct {
34+
}
35+
36+
func New(k8sClient client.Client) *Scheduler {
37+
ctx := context.WithValue(context.Background(), "component", "qemu-scheduler")
38+
logger := klog.FromContext(ctx)
39+
return &Scheduler{k8sClient: k8sClient, logger: logger}
40+
}
41+
42+
func (s *Scheduler) WithClient(client *proxmox.Service) *Scheduler {
43+
s.client = client
44+
return s
45+
}
46+
47+
// just poc codes
48+
// return randomly chosen node
49+
func (s *Scheduler) GetNode(ctx context.Context) (*api.Node, error) {
50+
if s.client == nil {
51+
return nil, fmt.Errorf("proxmox client is empty")
52+
}
53+
nodes, err := s.client.Nodes(ctx)
54+
if err != nil {
55+
return nil, err
56+
}
57+
if len(nodes) <= 0 {
58+
return nil, ErrNoNodesAvailable
59+
}
60+
src := rand.NewSource(time.Now().Unix())
61+
r := rand.New(src)
62+
return nodes[r.Intn(len(nodes))], nil
63+
}
64+
65+
// just poc codes
66+
// return nextID fetched from Proxmox rest API nextID endpoint
67+
func (s *Scheduler) GetID(ctx context.Context) (int, error) {
68+
return s.client.RESTClient().GetNextID(ctx)
69+
}
70+
71+
func (s *Scheduler) ScheduleQEMU() (ScheduleResult, error) {
72+
return ScheduleResult{}, nil
73+
}

cloud/scope/machine.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333

3434
infrav1 "github.com/sp-yduck/cluster-api-provider-proxmox/api/v1beta1"
3535
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/providerid"
36+
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/scheduler"
3637
)
3738

3839
type MachineScopeParams struct {
@@ -41,6 +42,7 @@ type MachineScopeParams struct {
4142
Machine *clusterv1.Machine
4243
ProxmoxMachine *infrav1.ProxmoxMachine
4344
ClusterGetter *ClusterScope
45+
Scheduler *scheduler.Scheduler
4446
}
4547

4648
func NewMachineScope(params MachineScopeParams) (*MachineScope, error) {
@@ -56,6 +58,9 @@ func NewMachineScope(params MachineScopeParams) (*MachineScope, error) {
5658
if params.ClusterGetter == nil {
5759
return nil, errors.New("failed to generate new scope form nil ClusterScope")
5860
}
61+
if params.Scheduler == nil {
62+
return nil, errors.New("failed to generate new scope form nil Scheduler")
63+
}
5964

6065
helper, err := patch.NewHelper(params.ProxmoxMachine, params.Client)
6166
if err != nil {
@@ -68,6 +73,7 @@ func NewMachineScope(params MachineScopeParams) (*MachineScope, error) {
6873
ProxmoxMachine: params.ProxmoxMachine,
6974
patchHelper: helper,
7075
ClusterGetter: params.ClusterGetter,
76+
Scheduler: params.Scheduler,
7177
}, err
7278
}
7379

@@ -77,12 +83,17 @@ type MachineScope struct {
7783
Machine *clusterv1.Machine
7884
ProxmoxMachine *infrav1.ProxmoxMachine
7985
ClusterGetter *ClusterScope
86+
Scheduler *scheduler.Scheduler
8087
}
8188

8289
func (m *MachineScope) CloudClient() *proxmox.Service {
8390
return m.ClusterGetter.CloudClient()
8491
}
8592

93+
func (m *MachineScope) GetScheduler() *scheduler.Scheduler {
94+
return m.Scheduler
95+
}
96+
8697
func (m *MachineScope) GetStorage() infrav1.Storage {
8798
return m.ClusterGetter.ProxmoxCluster.Spec.Storage
8899
}

cloud/services/compute/instance/qemu.go

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ package instance
33
import (
44
"context"
55
"fmt"
6-
"math/rand"
7-
"time"
86

9-
"github.com/pkg/errors"
107
"github.com/sp-yduck/proxmox-go/api"
118
"github.com/sp-yduck/proxmox-go/proxmox"
129
"github.com/sp-yduck/proxmox-go/rest"
@@ -50,19 +47,17 @@ func (s *Service) createQEMU(ctx context.Context, nodeName string, vmid *int) (*
5047

5148
// get node
5249
if nodeName == "" {
53-
// temp solution
54-
node, err := s.getRandomNode(ctx)
50+
node, err := s.scheduler.GetNode(ctx)
5551
if err != nil {
56-
log.Error(err, "failed to get random node")
52+
log.Error(err, "failed to get proxmox node")
5753
return nil, err
5854
}
59-
nodeName = node.Node
60-
s.scope.SetNodeName(nodeName)
55+
s.scope.SetNodeName(node.Node)
6156
}
6257

6358
// if vmid is empty, generate new vmid
6459
if vmid == nil {
65-
nextid, err := s.getNextID(ctx)
60+
nextid, err := s.scheduler.GetID(ctx)
6661
if err != nil {
6762
log.Error(err, "failed to get available vmid")
6863
return nil, err
@@ -73,7 +68,7 @@ func (s *Service) createQEMU(ctx context.Context, nodeName string, vmid *int) (*
7368
vmoption := s.generateVMOptions()
7469
vm, err := s.client.CreateVirtualMachine(ctx, nodeName, *vmid, vmoption)
7570
if err != nil {
76-
log.Error(err, fmt.Sprintf("failed to create qemu instance %s", vm.VM.Name))
71+
log.Error(err, "failed to create qemu instance")
7772
return nil, err
7873
}
7974
s.scope.SetVMID(*vmid)
@@ -83,28 +78,6 @@ func (s *Service) createQEMU(ctx context.Context, nodeName string, vmid *int) (*
8378
return vm, nil
8479
}
8580

86-
func (s *Service) getNextID(ctx context.Context) (int, error) {
87-
return s.client.RESTClient().GetNextID(ctx)
88-
}
89-
90-
func (s *Service) getNodes(ctx context.Context) ([]*api.Node, error) {
91-
return s.client.Nodes(ctx)
92-
}
93-
94-
// GetRandomNode returns a node chosen randomly
95-
func (s *Service) getRandomNode(ctx context.Context) (*api.Node, error) {
96-
nodes, err := s.getNodes(ctx)
97-
if err != nil {
98-
return nil, err
99-
}
100-
if len(nodes) <= 0 {
101-
return nil, errors.Errorf("no nodes found")
102-
}
103-
src := rand.NewSource(time.Now().Unix())
104-
r := rand.New(src)
105-
return nodes[r.Intn(len(nodes))], nil
106-
}
107-
10881
func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
10982
vmName := s.scope.Name()
11083
storageName := s.scope.GetStorage().Name

cloud/services/compute/instance/service.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@ import (
66
"github.com/sp-yduck/proxmox-go/proxmox"
77

88
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud"
9+
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/scheduler"
910
)
1011

1112
type Scope interface {
1213
cloud.Machine
1314
}
1415

1516
type Service struct {
16-
scope Scope
17-
client proxmox.Service
17+
scope Scope
18+
client proxmox.Service
19+
scheduler *scheduler.Scheduler
1820
}
1921

2022
func NewService(s Scope) *Service {
2123
return &Service{
22-
scope: s,
23-
client: *s.CloudClient(),
24+
scope: s,
25+
client: *s.CloudClient(),
26+
scheduler: s.GetScheduler().WithClient(s.CloudClient()),
2427
}
2528
}
2629

cmd/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"sigs.k8s.io/controller-runtime/pkg/log/zap"
3434

3535
infrastructurev1beta1 "github.com/sp-yduck/cluster-api-provider-proxmox/api/v1beta1"
36+
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/scheduler"
3637
controller "github.com/sp-yduck/cluster-api-provider-proxmox/controllers"
3738
//+kubebuilder:scaffold:imports
3839
)
@@ -93,8 +94,9 @@ func main() {
9394
}
9495

9596
if err = (&controller.ProxmoxMachineReconciler{
96-
Client: mgr.GetClient(),
97-
Scheme: mgr.GetScheme(),
97+
Client: mgr.GetClient(),
98+
Scheme: mgr.GetScheme(),
99+
Scheduler: scheduler.New(mgr.GetClient()),
98100
}).SetupWithManager(mgr); err != nil {
99101
setupLog.Error(err, "unable to create controller", "controller", "ProxmoxMachine")
100102
os.Exit(1)

controllers/proxmoxmachine_controller.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ import (
3434

3535
infrav1 "github.com/sp-yduck/cluster-api-provider-proxmox/api/v1beta1"
3636
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud"
37+
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/scheduler"
3738
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/scope"
3839
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/services/compute/instance"
3940
)
4041

4142
// ProxmoxMachineReconciler reconciles a ProxmoxMachine object
4243
type ProxmoxMachineReconciler struct {
4344
client.Client
44-
Scheme *runtime.Scheme
45+
Scheme *runtime.Scheme
46+
Scheduler *scheduler.Scheduler
4547
}
4648

4749
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=proxmoxmachines,verbs=get;list;watch;create;update;patch;delete
@@ -115,6 +117,7 @@ func (r *ProxmoxMachineReconciler) Reconcile(ctx context.Context, req ctrl.Reque
115117
Machine: machine,
116118
ProxmoxMachine: proxmoxMachine,
117119
ClusterGetter: clusterScope,
120+
Scheduler: r.Scheduler,
118121
})
119122
if err != nil {
120123
return ctrl.Result{}, errors.Errorf("failed to create scope: %+v", err)

0 commit comments

Comments
 (0)