44package v1alpha1
55
66import (
7+ "crypto/rand"
8+ "fmt"
9+
710 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
811)
912
@@ -16,7 +19,7 @@ type DeviceSpec struct {
1619 // Bootstrap is an optional configuration for the device bootstrap process.
1720 // It can be used to provide initial configuration templates or scripts that are applied during the device provisioning.
1821 // +optional
19- Bootstrap * Bootstrap `json:"bootstrap ,omitempty"`
22+ Provisioning * Provisioning `json:"provisioning ,omitempty"`
2023}
2124
2225// Endpoint contains the connection information for the device.
@@ -48,11 +51,40 @@ type TLS struct {
4851 Certificate * CertificateSource `json:"certificate,omitempty"`
4952}
5053
51- // Bootstrap defines the configuration for device bootstrap.
52- type Bootstrap struct {
53- // Template defines the multiline string template that contains the initial configuration for the device.
54+ // Provisioning defines the configuration for device bootstrap.
55+ type Provisioning struct {
56+ // Image defines the image to be used for provisioning the device.
5457 // +required
55- Template TemplateSource `json:"template"`
58+ Image Image `json:"image"`
59+
60+ // BootScript defines the script delivered by a TFTP server to the device during bootstrapping.
61+ // +optional
62+ BootScript TemplateSource `json:"bootScript"`
63+ }
64+
65+ // ChecksumType defines the type of checksum used for image verification.
66+ // +kubebuilder:validation:Enum=SHA256;MD5
67+ type ChecksumType string
68+
69+ const (
70+ ChecksumTypeSHA256 ChecksumType = "SHA256"
71+ ChecksumTypeMD5 ChecksumType = "MD5"
72+ )
73+
74+ type Image struct {
75+ // URL is the location of the image to be used for provisioning.
76+ // +required
77+ URL string `json:"url"`
78+
79+ // Checksum is the checksum of the image for verification.
80+ // +required
81+ // kubebuilder:validation:MinLength=1
82+ Checksum string `json:"checksum"`
83+
84+ // ChecksumType is the type of the checksum (e.g., sha256, md5).
85+ // +required
86+ // +kubebuilder:default=MD5
87+ ChecksumType ChecksumType `json:"checksumType"`
5688}
5789
5890// TemplateSource defines a source for template content.
@@ -105,6 +137,14 @@ type DeviceStatus struct {
105137 // +optional
106138 FirmwareVersion string `json:"firmwareVersion,omitempty"`
107139
140+ // Provisioning is the list of provisioning attempts for the Device.
141+ //+listType=map
142+ //+listMapKey=startTime
143+ //+patchStrategy=merge
144+ //+patchMergeKey=startTime
145+ //+optional
146+ Provisioning []ProvisioningInfo `json:"provisioning,omitempty"`
147+
108148 // Ports is the list of ports on the Device.
109149 // +optional
110150 Ports []DevicePort `json:"ports,omitempty"`
@@ -122,6 +162,41 @@ type DeviceStatus struct {
122162 Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
123163}
124164
165+ type ProvisioningInfo struct {
166+ StartTime metav1.Time `json:"startTime"`
167+ EndTime metav1.Time `json:"endTime,omitempty"`
168+ Token string `json:"token"`
169+ Error string `json:"error,omitempty"`
170+ }
171+
172+ func (d * Device ) GetActiveProvisioning () * ProvisioningInfo {
173+ for i := range d .Status .Provisioning {
174+ if d .Status .Provisioning [i ].EndTime .IsZero () {
175+ return & d .Status .Provisioning [i ]
176+ }
177+ }
178+ return nil
179+ }
180+
181+ func (d * Device ) CreateProvisioningEntry () (* ProvisioningInfo , error ) {
182+
183+ if d .Status .Phase != DevicePhaseProvisioning {
184+ return nil , fmt .Errorf ("device is in phase %s, expected %s" , d .Status .Phase , DevicePhaseProvisioning )
185+ }
186+ active := d .GetActiveProvisioning ()
187+ if active != nil {
188+ return nil , fmt .Errorf ("device has an active provisioning with StartTime %s" , active .StartTime .String ())
189+ }
190+ token := make ([]byte , 32 )
191+ rand .Read (token )
192+ entry := ProvisioningInfo {
193+ StartTime : metav1 .Now (),
194+ Token : fmt .Sprintf ("%x" , token ),
195+ }
196+ d .Status .Provisioning = append (d .Status .Provisioning , entry )
197+ return & d .Status .Provisioning [len (d .Status .Provisioning )- 1 ], nil
198+ }
199+
125200type DevicePort struct {
126201 // Name is the name of the port.
127202 // +required
@@ -137,7 +212,7 @@ type DevicePort struct {
137212
138213 // Transceiver is the type of transceiver plugged into the port, if any.
139214 // +optional
140- Trasceiver string `json:"transceiver,omitempty"`
215+ Transceiver string `json:"transceiver,omitempty"`
141216
142217 // InterfaceRef is the reference to the corresponding Interface resource
143218 // configuring this port, if any.
@@ -146,14 +221,16 @@ type DevicePort struct {
146221}
147222
148223// DevicePhase represents the current phase of the Device as it's being provisioned and managed by the operator.
149- // +kubebuilder:validation:Enum=Pending;Provisioning;Active;Failed
224+ // +kubebuilder:validation:Enum=Pending;Provisioning;Active;Failed;ProvisioningCompleted
150225type DevicePhase string
151226
152227const (
153228 // DevicePhasePending indicates that the device is pending and has not yet been provisioned.
154229 DevicePhasePending DevicePhase = "Pending"
155230 // DevicePhaseProvisioning indicates that the device is being provisioned.
156231 DevicePhaseProvisioning DevicePhase = "Provisioning"
232+ // DevicePhaseProvisioningCompleted indicates that the device provisioning has completed and the operator is performing post-provisioning tasks.
233+ DevicePhaseProvisioningCompleted DevicePhase = "ProvisioningCompleted"
157234 // DevicePhaseActive indicates that the device has been successfully provisioned and is now ready for use.
158235 DevicePhaseActive DevicePhase = "Active"
159236 // DevicePhaseFailed indicates that the device provisioning has failed.
@@ -211,11 +288,6 @@ func (d *Device) GetSecretRefs() []SecretReference {
211288 refs = append (refs , d .Spec .Endpoint .TLS .Certificate .SecretRef )
212289 }
213290 }
214- if d .Spec .Bootstrap != nil {
215- if d .Spec .Bootstrap .Template .SecretRef != nil {
216- refs = append (refs , d .Spec .Bootstrap .Template .SecretRef .SecretReference )
217- }
218- }
219291 for i := range refs {
220292 if refs [i ].Namespace == "" {
221293 refs [i ].Namespace = d .Namespace
@@ -227,11 +299,6 @@ func (d *Device) GetSecretRefs() []SecretReference {
227299// GetConfigMapRefs returns the list of configmaps referenced in the [Device] resource.
228300func (d * Device ) GetConfigMapRefs () []ConfigMapReference {
229301 refs := []ConfigMapReference {}
230- if d .Spec .Bootstrap != nil {
231- if d .Spec .Bootstrap .Template .ConfigMapRef != nil {
232- refs = append (refs , d .Spec .Bootstrap .Template .ConfigMapRef .ConfigMapReference )
233- }
234- }
235302 for i := range refs {
236303 if refs [i ].Namespace == "" {
237304 refs [i ].Namespace = d .Namespace
0 commit comments