Skip to content

Commit c5d6211

Browse files
authored
Merge pull request #63 from sp-yduck/feature/image-format
Feature/image format
2 parents e6bf195 + 86e7a06 commit c5d6211

11 files changed

+81
-28
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,21 @@ kubectl delete cluster cappx-test
5959

6060
- No need to prepare vm templates. You can specify any vm image in `ProxmoxMachine.Spec.Image`. CAPPX bootstrap your vm from scratch.
6161

62-
- Supports qcow2 image format. CAPPX uses VNC websocket for downloading/installing node images so it can support raw image format not ISO (Proxmox API can only support ISO)
62+
- Supports mutiple image format. CAPPX uses VNC websocket for downloading/installing node images so it can support multiple image format not only ISO (Proxmox API can only support ISO)
6363

6464
- Supports custom cloud-config (user data). CAPPX uses VNC websockert for bootstrapping nodes so it can applies custom cloud-config that can not be achieved by only Proxmox API.
6565

6666
### Node Images
6767

68-
CAPPX is compatible with `qcow2` image. You can build your own node image and use it for `ProxmoxMachine`.
68+
CAPPX is compatible with `iso`, `qcow2`, `qed`, `raw`, `vdi`, `vpc`, `vmdk` format of image. You can build your own node image and use it for `ProxmoxMachine`.
6969

7070
CAPPX relies on a few prerequisites which have to be already installed in the used operating system images, e.g. a container runtime, kubelet, kubeadm,.. .
7171

7272
To build your custom node image, you can use [kubernetes-sigs/image-builder](https://github.com/kubernetes-sigs/image-builder) project.
7373

7474
Also there are some available out-of-box images published other communities such as [Metal3](https://github.com/metal3-io). For example https://artifactory.nordix.org/ui/native/metal3/images/. Example MD can be found [metal3-ubuntu2204-k8s127.yaml](examples/machine_deployment/metal3-ubuntu2204-k8s127.yaml).
7575

76-
If it isn't possible to pre-install those prerequisites in the image, you can always deploy and execute some custom scripts through the `ProxmoxMachine.spec.cloudInit` or `KubeadmConfig` . Example MD can be found [ubuntu2204.yaml](examples/machine_deployment/ubuntu2204.yaml).
76+
If it isn't possible to pre-install those prerequisites in the image, you can always deploy and execute some custom scripts through the `ProxmoxMachine.spec.cloudInit` or `KubeadmConfig`. Example MD can be found [ubuntu2204.yaml](examples/machine_deployment/ubuntu2204.yaml).
7777

7878
## Compatibility
7979

api/v1beta1/proxmoxmachine_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type ProxmoxMachineSpec struct {
3737
// +optional
3838
Node string `json:"node,omitempty"`
3939

40+
// +kubebuilder:validation:Minimum:=0
4041
// VMID is proxmox qemu's id
4142
// +optional
4243
VMID *int `json:"vmID,omitempty"`

api/v1beta1/type.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,9 @@ type ServerRef struct {
1212
// endpoint is the address of the Proxmox-VE REST API endpoint.
1313
Endpoint string `json:"endpoint"`
1414

15-
// to do : login type should be an option
16-
// user&pass or token
17-
1815
// to do : client options like insecure tls verify
1916

2017
// SecretRef is a reference for secret which contains proxmox login secrets
21-
// and ssh configs for proxmox nodes
2218
SecretRef *ObjectReference `json:"secretRef"`
2319
}
2420

@@ -36,12 +32,18 @@ type ObjectReference struct {
3632

3733
// Image is the image to be provisioned
3834
type Image struct {
35+
// +kubebuilder:validation:Pattern:=.*\.(iso|img|qcow2|qed|raw|vdi|vpc|vmdk)$
3936
// URL is a location of an image to deploy.
37+
// supported formats are iso/qcow2/qed/raw/vdi/vpc/vmdk.
4038
URL string `json:"url"`
4139

4240
// Checksum
41+
// Always better to specify checksum otherwise cappx will download
42+
// same image for every time. If checksum is specified, cappx will try
43+
// to avoid downloading existing image.
4344
Checksum string `json:"checksum,omitempty"`
4445

46+
// +kubebuilder:validation:Enum:=sha256;sha256sum;md5;md5sum
4547
// ChecksumType
4648
ChecksumType *string `json:"checksumType,omitempty"`
4749
}
@@ -100,7 +102,8 @@ type Network struct {
100102
SearchDomain string `json:"searchDomain,omitempty"`
101103
}
102104

103-
// IPConfig defines IP addresses and gateways for corresponding interface
105+
// IPConfig defines IP addresses and gateways for corresponding interface.
106+
// it defaults to using dhcp on IPv4 if neither IP nor IP6 is specified.
104107
type IPConfig struct {
105108
// IPv4 with CIDR
106109
IP string `json:"ip,omitempty"`

cloud/interfaces.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ type MachineSetter interface {
7676
// SetFailureReason(v capierrors.MachineStatusError)
7777
// SetAnnotation(key, value string)
7878
// SetAddresses(addressList []corev1.NodeAddress)
79+
PatchObject() error
7980
}
8081

8182
// Machine is an interface which can get and set machine information.

cloud/services/compute/instance/image.go

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/pkg/errors"
1010
"github.com/sp-yduck/proxmox-go/proxmox"
1111
"sigs.k8s.io/controller-runtime/pkg/log"
12+
13+
infrav1 "github.com/sp-yduck/cluster-api-provider-proxmox/api/v1beta1"
1214
)
1315

1416
const (
@@ -40,9 +42,7 @@ func (s *Service) setCloudImage(ctx context.Context) error {
4042
log.Info("setting cloud image")
4143

4244
image := s.scope.GetImage()
43-
url := image.URL
44-
fileName := path.Base(url)
45-
rawImageFilePath := fmt.Sprintf("%s/%s", rawImageDirPath, fileName)
45+
rawImageFilePath := rawImageFilePath(image)
4646

4747
// workaround
4848
// API does not support something equivalent of "qm importdisk"
@@ -51,27 +51,24 @@ func (s *Service) setCloudImage(ctx context.Context) error {
5151
return errors.Errorf("failed to create vnc client: %v", err)
5252
}
5353
defer vnc.Close()
54-
out, _, err := vnc.Exec(ctx, fmt.Sprintf("wget %s --directory-prefix %s -nc", url, rawImageDirPath))
55-
if err != nil {
56-
return errors.Errorf("failed to download image: %s : %v", out, err)
57-
}
5854

59-
// checksum
60-
if image.Checksum != "" {
61-
cscmd, err := findValidChecksumCommand(*image.ChecksumType)
55+
// download image
56+
ok, _ := isChecksumOK(vnc, image, rawImageFilePath)
57+
if !ok { // if checksum is ok, it means the image is already there. skip installing
58+
log.Info("downloading node image. this will take few mins.")
59+
out, _, err := vnc.Exec(ctx, fmt.Sprintf("wget %s -O %s", image.URL, rawImageFilePath))
6260
if err != nil {
63-
return err
61+
return errors.Errorf("failed to download image: %s : %v", out, err)
6462
}
65-
cmd := fmt.Sprintf("echo -n '%s %s' | %s --check -", image.Checksum, rawImageFilePath, cscmd)
66-
out, _, err = vnc.Exec(context.TODO(), cmd)
67-
if err != nil {
68-
return errors.Errorf("failed to confirm checksum: %s : %v", out, err)
63+
if _, err = isChecksumOK(vnc, image, rawImageFilePath); err != nil {
64+
return errors.Errorf("failed to confirm checksum: %v", err)
6965
}
7066
}
7167

68+
// convert downloaded image to raw format and set it to storage
7269
vmid := s.scope.GetVMID()
7370
destPath := fmt.Sprintf("%s/images/%d/vm-%d-disk-0.raw", s.scope.GetStorage().Path, *vmid, *vmid)
74-
out, _, err = vnc.Exec(context.TODO(), fmt.Sprintf("/usr/bin/qemu-img convert -O raw %s %s", rawImageFilePath, destPath))
71+
out, _, err := vnc.Exec(context.TODO(), fmt.Sprintf("/usr/bin/qemu-img convert -O raw %s %s", rawImageFilePath, destPath))
7572
if err != nil {
7673
return errors.Errorf("failed to convert iamge : %s : %v", out, err)
7774
}
@@ -89,3 +86,27 @@ func findValidChecksumCommand(csType string) (string, error) {
8986
return "", errors.Errorf("checksum type %s is not supported", csType)
9087
}
9188
}
89+
90+
func isChecksumOK(client *proxmox.VNCWebSocketClient, image infrav1.Image, path string) (bool, error) {
91+
if image.Checksum != "" {
92+
cscmd, err := findValidChecksumCommand(*image.ChecksumType)
93+
if err != nil {
94+
return false, err
95+
}
96+
cmd := fmt.Sprintf("echo -n '%s %s' | %s --check -", image.Checksum, path, cscmd)
97+
out, _, err := client.Exec(context.TODO(), cmd)
98+
if err != nil {
99+
return false, errors.Errorf("failed to confirm checksum: %s : %v", out, err)
100+
}
101+
return true, nil
102+
}
103+
return false, nil
104+
}
105+
106+
func rawImageFilePath(image infrav1.Image) string {
107+
fileName := path.Base(image.URL)
108+
if image.Checksum != "" {
109+
fileName = image.Checksum + "." + fileName
110+
}
111+
return fmt.Sprintf("%s/%s", rawImageDirPath, fileName)
112+
}

cloud/services/compute/instance/qemu.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ func (s *Service) createQEMU(ctx context.Context, nodeName string, vmid *int) (*
6868
}
6969
vmid = &nextid
7070
s.scope.SetVMID(*vmid)
71+
if err := s.scope.PatchObject(); err != nil {
72+
return nil, err
73+
}
7174
}
7275

7376
vmoption := s.generateVMOptions()

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxclusters.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ spec:
7676
type: string
7777
secretRef:
7878
description: SecretRef is a reference for secret which contains
79-
proxmox login secrets and ssh configs for proxmox nodes
79+
proxmox login secrets
8080
properties:
8181
name:
8282
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachines.yaml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,22 @@ spec:
134134
description: Image is the image to be provisioned
135135
properties:
136136
checksum:
137-
description: Checksum
137+
description: Checksum Always better to specify checksum otherwise
138+
cappx will download same image for every time. If checksum is
139+
specified, cappx will try to avoid downloading existing image.
138140
type: string
139141
checksumType:
140142
description: ChecksumType
143+
enum:
144+
- sha256
145+
- sha256sum
146+
- md5
147+
- md5sum
141148
type: string
142149
url:
143-
description: URL is a location of an image to deploy.
150+
description: URL is a location of an image to deploy. supported
151+
formats are iso/qcow2/qed/raw/vdi/vpc/vmdk.
152+
pattern: .*\.(iso|img|qcow2|qed|raw|vdi|vpc|vmdk)$
144153
type: string
145154
required:
146155
- url
@@ -320,6 +329,7 @@ spec:
320329
type: string
321330
vmID:
322331
description: VMID is proxmox qemu's id
332+
minimum: 0
323333
type: integer
324334
required:
325335
- image

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachinetemplates.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,23 @@ spec:
159159
description: Image is the image to be provisioned
160160
properties:
161161
checksum:
162-
description: Checksum
162+
description: Checksum Always better to specify checksum
163+
otherwise cappx will download same image for every time.
164+
If checksum is specified, cappx will try to avoid downloading
165+
existing image.
163166
type: string
164167
checksumType:
165168
description: ChecksumType
169+
enum:
170+
- sha256
171+
- sha256sum
172+
- md5
173+
- md5sum
166174
type: string
167175
url:
168176
description: URL is a location of an image to deploy.
177+
supported formats are iso/qcow2/qed/raw/vdi/vpc/vmdk.
178+
pattern: .*\.(iso|img|qcow2|qed|raw|vdi|vpc|vmdk)$
169179
type: string
170180
required:
171181
- url
@@ -351,6 +361,7 @@ spec:
351361
type: string
352362
vmID:
353363
description: VMID is proxmox qemu's id
364+
minimum: 0
354365
type: integer
355366
required:
356367
- image

controllers/proxmoxcluster_controller.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ func (r *ProxmoxClusterReconciler) reconcile(ctx context.Context, clusterScope *
133133
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
134134
}
135135

136+
log.Info("Reconciled ProxmoxCluster")
136137
record.Eventf(clusterScope.ProxmoxCluster, "ProxmoxClusterReconcile", "Got control-plane endpoint - %s", controlPlaneEndpoint.Host)
137138
clusterScope.SetReady()
138139
record.Event(clusterScope.ProxmoxCluster, "ProxmoxClusterReconcile", "Reconciled")
@@ -155,6 +156,7 @@ func (r *ProxmoxClusterReconciler) reconcileDelete(ctx context.Context, clusterS
155156
}
156157
}
157158

159+
log.Info("Reconciled ProxmoxCluster")
158160
controllerutil.RemoveFinalizer(clusterScope.ProxmoxCluster, infrav1.ClusterFinalizer)
159161
record.Event(clusterScope.ProxmoxCluster, "ProxmoxClusterReconcile", "Reconciled")
160162
return ctrl.Result{}, nil

0 commit comments

Comments
 (0)