Skip to content

Commit 133a7c0

Browse files
committed
resolve conflict
2 parents 9be7e04 + b8a1ca9 commit 133a7c0

14 files changed

+127
-58
lines changed

api/v1beta1/proxmoxcluster_types.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ type ProxmoxClusterSpec struct {
3535
// ServerRef is used for configuring Proxmox client
3636
ServerRef ServerRef `json:"serverRef"`
3737

38-
// storage is for proxmox storage used by vm instances
39-
// +optional
40-
Storage Storage `json:"storage"`
38+
// storage is used for storing cloud init snippet
39+
Storage Storage `json:"storage,omitempty"`
4140
}
4241

4342
// ProxmoxClusterStatus defines the observed state of ProxmoxCluster

api/v1beta1/proxmoxmachine_types.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,22 @@ type ProxmoxMachineSpec struct {
3434
ProviderID *string `json:"providerID,omitempty"`
3535

3636
// Node is proxmox node hosting vm instance which used for ProxmoxMachine
37-
// +optional
3837
Node string `json:"node,omitempty"`
3938

39+
// Storage is name of proxmox storage used by this node.
40+
// The storage must support "images(VM Disks)" type of content.
41+
// cappx will use random storage if empty
42+
Storage string `json:"storage,omitempty"`
43+
4044
// +kubebuilder:validation:Minimum:=0
4145
// VMID is proxmox qemu's id
42-
// +optional
4346
VMID *int `json:"vmID,omitempty"`
4447

4548
// Image is the image to be provisioned
4649
Image Image `json:"image"`
4750

4851
// CloudInit defines options related to the bootstrapping systems where
4952
// CloudInit is used.
50-
// +optional
5153
CloudInit CloudInit `json:"cloudInit,omitempty"`
5254

5355
// Hardware
@@ -56,8 +58,7 @@ type ProxmoxMachineSpec struct {
5658
// Network
5759
Network Network `json:"network,omitempty"`
5860

59-
// Options
60-
// +optional
61+
// Options for QEMU instance
6162
Options Options `json:"options,omitempty"`
6263

6364
// FailureDomain is the failure domain unique identifier this Machine should be attached to, as defined in Cluster API.
@@ -94,7 +95,9 @@ type ProxmoxMachineStatus struct {
9495
//+kubebuilder:subresource:status
9596
// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels.cluster\\.x-k8s\\.io/cluster-name",description="Cluster to which this VSphereMachine belongs"
9697
// +kubebuilder:printcolumn:name="Machine",type="string",JSONPath=".metadata.ownerReferences[?(@.kind==\"Machine\")].name",description="Machine object which owns with this ProxmoxMachine",priority=1
97-
// +kubebuilder:printcolumn:name="vmid",type=string,JSONPath=`.spec.vmID`,priority=1
98+
// +kubebuilder:printcolumn:name="VMID",type=string,JSONPath=`.spec.vmID`,priority=1
99+
// +kubebuilder:printcolumn:name="Node",type=string,JSONPath=`.spec.node`,priority=1
100+
// +kubebuilder:printcolumn:name="Storage",type=string,JSONPath=`.spec.storage`,priority=1
98101
// +kubebuilder:printcolumn:name="ProviderID",type=string,JSONPath=`.spec.providerID`
99102
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.instanceStatus`
100103
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of Machine"

cloud/interfaces.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ type MachineGetter interface {
6060
GetProviderID() string
6161
GetBootstrapData() (string, error)
6262
GetInstanceStatus() *infrav1.InstanceStatus
63-
GetStorage() infrav1.Storage
63+
GetClusterStorage() infrav1.Storage
64+
GetStorage() string
6465
GetCloudInit() infrav1.CloudInit
6566
GetNetwork() infrav1.Network
6667
GetHardware() infrav1.Hardware
@@ -75,6 +76,7 @@ type MachineSetter interface {
7576
SetNodeName(name string)
7677
SetVMID(vmid int)
7778
SetConfigStatus(config api.VirtualMachineConfig)
79+
SetStorage(name string)
7880
// SetFailureMessage(v error)
7981
// SetFailureReason(v capierrors.MachineStatusError)
8082
// SetAnnotation(key, value string)

cloud/scope/cluster.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package scope
1818

1919
import (
2020
"context"
21+
"fmt"
2122

2223
"github.com/pkg/errors"
2324
"github.com/sp-yduck/proxmox-go/proxmox"
@@ -26,6 +27,7 @@ import (
2627
"sigs.k8s.io/controller-runtime/pkg/client"
2728

2829
infrav1 "github.com/sp-yduck/cluster-api-provider-proxmox/api/v1beta1"
30+
"github.com/sp-yduck/cluster-api-provider-proxmox/cloud/services/compute/storage"
2931
)
3032

3133
type ClusterScopeParams struct {
@@ -92,7 +94,14 @@ func (s *ClusterScope) ControlPlaneEndpoint() clusterv1.APIEndpoint {
9294
return s.ProxmoxCluster.Spec.ControlPlaneEndpoint
9395
}
9496

97+
// return default values if they are not specified
9598
func (s *ClusterScope) Storage() infrav1.Storage {
99+
if s.ProxmoxCluster.Spec.Storage.Name == "" {
100+
s.ProxmoxCluster.Spec.Storage.Name = fmt.Sprintf("local-dir-%s", s.Name())
101+
}
102+
if s.ProxmoxCluster.Spec.Storage.Path == "" {
103+
s.ProxmoxCluster.Spec.Storage.Path = fmt.Sprintf("%s/%s", storage.DefaultBasePath, s.ProxmoxCluster.Spec.Storage.Name)
104+
}
96105
return s.ProxmoxCluster.Spec.Storage
97106
}
98107

cloud/scope/machine.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,12 @@ func (m *MachineScope) GetScheduler(client *proxmox.Service) *scheduler.Schedule
9494
return m.SchedulerManager.GetScheduler(client)
9595
}
9696

97-
func (m *MachineScope) GetStorage() infrav1.Storage {
98-
return m.ClusterGetter.ProxmoxCluster.Spec.Storage
97+
func (m *MachineScope) GetClusterStorage() infrav1.Storage {
98+
return m.ClusterGetter.Storage()
99+
}
100+
101+
func (m *MachineScope) GetStorage() string {
102+
return m.ProxmoxMachine.Spec.Storage
99103
}
100104

101105
func (m *MachineScope) Name() string {
@@ -118,6 +122,10 @@ func (m *MachineScope) SetNodeName(name string) {
118122
m.ProxmoxMachine.Spec.Node = name
119123
}
120124

125+
func (m *MachineScope) SetStorage(name string) {
126+
m.ProxmoxMachine.Spec.Storage = name
127+
}
128+
121129
// func (m *MachineScope) Client() Compute {
122130
// return m.ClusterGetter.Client()
123131
// }

cloud/services/compute/instance/cloudinit.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (s *Service) reconcileCloudInit(ctx context.Context) error {
3030

3131
// delete CloudConfig
3232
func (s *Service) deleteCloudConfig(ctx context.Context) error {
33-
storageName := s.scope.GetStorage().Name
33+
storageName := s.scope.GetClusterStorage().Name
3434
path := userSnippetPath(s.scope.Name())
3535
volumeID := fmt.Sprintf("%s:%s", storageName, path)
3636

@@ -79,7 +79,7 @@ func (s *Service) reconcileCloudInitUser(ctx context.Context) error {
7979
return err
8080
}
8181
defer vnc.Close()
82-
filePath := fmt.Sprintf("%s/%s", s.scope.GetStorage().Path, userSnippetPath(vmName))
82+
filePath := fmt.Sprintf("%s/%s", s.scope.GetClusterStorage().Path, userSnippetPath(vmName))
8383
if err := vnc.WriteFile(context.TODO(), configYaml, filePath); err != nil {
8484
return errors.Errorf("failed to write file error : %v", err)
8585
}

cloud/services/compute/instance/image.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,14 @@ func (s *Service) reconcileBootDevice(ctx context.Context, vm *proxmox.VirtualMa
3636
}
3737

3838
// setCloudImage downloads OS image into Proxmox node
39-
// and then sets it to specified storage
39+
// so that proxmox can import image to the storage from there
4040
func (s *Service) setCloudImage(ctx context.Context) error {
4141
log := log.FromContext(ctx)
4242
log.Info("setting cloud image")
4343

4444
image := s.scope.GetImage()
4545
rawImageFilePath := rawImageFilePath(image)
4646

47-
// workaround
48-
// API does not support something equivalent of "qm importdisk"
4947
vnc, err := s.vncClient(s.scope.NodeName())
5048
if err != nil {
5149
return errors.Errorf("failed to create vnc client: %v", err)
@@ -68,14 +66,6 @@ func (s *Service) setCloudImage(ctx context.Context) error {
6866
return errors.Errorf("failed to confirm checksum: %v", err)
6967
}
7068
}
71-
72-
// convert downloaded image to raw format and set it to storage
73-
vmid := s.scope.GetVMID()
74-
destPath := fmt.Sprintf("%s/images/%d/vm-%d-disk-0.raw", s.scope.GetStorage().Path, *vmid, *vmid)
75-
out, _, err := vnc.Exec(context.TODO(), fmt.Sprintf("/usr/bin/qemu-img convert -O raw %s %s", rawImageFilePath, destPath))
76-
if err != nil {
77-
return errors.Errorf("failed to convert iamge : %s : %v", out, err)
78-
}
7969
return nil
8070
}
8171

cloud/services/compute/instance/qemu.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@ func (s *Service) getQEMU(ctx context.Context) (*proxmox.VirtualMachine, error)
4545
func (s *Service) createQEMU(ctx context.Context) (*proxmox.VirtualMachine, error) {
4646
log := log.FromContext(ctx)
4747

48-
// bind annotation key-values to context
49-
schedCtx := framework.ContextWithMap(ctx, s.scope.Annotations())
48+
if err := s.ensureStorageAvailable(ctx); err != nil {
49+
return nil, err
50+
}
5051

51-
// node assignment
52+
// create qemu
5253
vmoption := s.generateVMOptions()
54+
// bind annotation key-values to context
55+
schedCtx := framework.ContextWithMap(ctx, s.scope.Annotations())
5356
result, err := s.scheduler.CreateQEMU(schedCtx, &vmoption)
5457
if err != nil {
5558
log.Error(err, "failed to create qemu instance")
@@ -66,10 +69,15 @@ func (s *Service) createQEMU(ctx context.Context) (*proxmox.VirtualMachine, erro
6669

6770
func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
6871
vmName := s.scope.Name()
69-
storageName := s.scope.GetStorage().Name
72+
snippetStorageName := s.scope.GetClusterStorage().Name
73+
imageStorageName := s.scope.GetStorage()
7074
network := s.scope.GetNetwork()
7175
hardware := s.scope.GetHardware()
7276
options := s.scope.GetOptions()
77+
cicustom := fmt.Sprintf("user=%s:%s", snippetStorageName, userSnippetPath(vmName))
78+
ide2 := fmt.Sprintf("file=%s:cloudinit,media=cdrom", imageStorageName)
79+
scsi0 := fmt.Sprintf("%s:0,import-from=%s", imageStorageName, rawImageFilePath(s.scope.GetImage()))
80+
net0 := "model=virtio,bridge=vmbr0,firewall=1"
7381

7482
vmoptions := api.VirtualMachineCreateOptions{
7583
ACPI: boolToInt8(options.ACPI),
@@ -78,12 +86,12 @@ func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
7886
Balloon: options.Balloon,
7987
BIOS: string(hardware.BIOS),
8088
Boot: fmt.Sprintf("order=%s", bootDvice),
81-
CiCustom: fmt.Sprintf("user=%s:%s", storageName, userSnippetPath(vmName)),
89+
CiCustom: cicustom,
8290
Cores: hardware.CPU,
8391
CpuLimit: hardware.CPULimit,
8492
Description: options.Description,
8593
HugePages: options.HugePages.String(),
86-
Ide: api.Ide{Ide2: fmt.Sprintf("file=%s:cloudinit,media=cdrom", storageName)},
94+
Ide: api.Ide{Ide2: ide2},
8795
IPConfig: api.IPConfig{IPConfig0: network.IPConfig.String()},
8896
KeepHugePages: boolToInt8(options.KeepHugePages),
8997
KVM: boolToInt8(options.KVM),
@@ -92,14 +100,14 @@ func (s *Service) generateVMOptions() api.VirtualMachineCreateOptions {
92100
Memory: hardware.Memory,
93101
Name: vmName,
94102
NameServer: network.NameServer,
95-
Net: api.Net{Net0: "model=virtio,bridge=vmbr0,firewall=1"},
103+
Net: api.Net{Net0: net0},
96104
Numa: boolToInt8(options.NUMA),
97105
Node: s.scope.NodeName(),
98106
OnBoot: boolToInt8(options.OnBoot),
99107
OSType: api.OSType(options.OSType),
100108
Protection: boolToInt8(options.Protection),
101109
Reboot: int(boolToInt8(options.Reboot)),
102-
Scsi: api.Scsi{Scsi0: fmt.Sprintf("file=%s:8", storageName)},
110+
Scsi: api.Scsi{Scsi0: scsi0},
103111
ScsiHw: api.VirtioScsiPci,
104112
SearchDomain: network.SearchDomain,
105113
Serial: api.Serial{Serial0: "socket"},
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package instance
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/sp-yduck/proxmox-go/api"
9+
)
10+
11+
// make sure storage exists and supports "images" type of content
12+
func (s *Service) ensureStorageAvailable(ctx context.Context) error {
13+
storageName := s.scope.GetStorage()
14+
if storageName == "" { // no storage specified, find available storage
15+
storage, err := s.findVMStorage(ctx)
16+
if err != nil {
17+
return err
18+
}
19+
storageName = storage.Storage
20+
s.scope.SetStorage(storageName)
21+
} else { // storage specified, check if it supports "images" type of content
22+
storage, err := s.client.RESTClient().GetStorage(ctx, storageName)
23+
if err != nil {
24+
return err
25+
}
26+
if supportsImage(storage) {
27+
return fmt.Errorf("storage %s does not support \"images\" type of content", storageName)
28+
}
29+
}
30+
return nil
31+
}
32+
33+
// get one storage supporting "images" type of content
34+
func (s *Service) findVMStorage(ctx context.Context) (*api.Storage, error) {
35+
storages, err := s.client.RESTClient().GetStorages(ctx)
36+
if err != nil {
37+
return nil, err
38+
}
39+
for _, storage := range storages {
40+
if supportsImage(storage) {
41+
return storage, nil
42+
}
43+
}
44+
return nil, fmt.Errorf("no available storage")
45+
}
46+
47+
func supportsImage(storage *api.Storage) bool {
48+
return strings.Contains(storage.Content, "images")
49+
}

cloud/services/compute/storage/reconcile.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package storage
22

33
import (
44
"context"
5-
"errors"
6-
"fmt"
75

86
"github.com/sp-yduck/proxmox-go/api"
97
"github.com/sp-yduck/proxmox-go/proxmox"
@@ -14,7 +12,7 @@ import (
1412
)
1513

1614
const (
17-
defaultBasePath = "/var/lib/vz"
15+
DefaultBasePath = "/var/lib/vz"
1816
)
1917

2018
func (s *Service) Reconcile(ctx context.Context) error {
@@ -91,7 +89,8 @@ func (s *Service) deleteStorage(ctx context.Context) error {
9189
return err
9290
}
9391
if len(contents) > 0 {
94-
return errors.New("Storage must be empty to be deleted")
92+
log.Info("storage not empty, skipping deletion")
93+
return nil
9594
}
9695
}
9796

@@ -108,15 +107,9 @@ func generateVMStorageOptions(scope Scope) api.StorageCreateOptions {
108107
options := api.StorageCreateOptions{
109108
Storage: storageSpec.Name,
110109
StorageType: "dir",
111-
Content: "images,snippets",
110+
Content: "snippets",
112111
Mkdir: &mkdir,
113112
Path: storageSpec.Path,
114113
}
115-
if options.Storage == "" {
116-
options.Storage = fmt.Sprintf("local-dir-%s", scope.Name())
117-
}
118-
if options.Path == "" {
119-
options.Path = fmt.Sprintf("%s/%s", defaultBasePath, options.Storage)
120-
}
121114
return options
122115
}

0 commit comments

Comments
 (0)