Skip to content

Commit bbd27bb

Browse files
author
Richard Kovacs
committed
Requeue non empty vpc deletion
1 parent 23c8c0a commit bbd27bb

12 files changed

+168
-92
lines changed

api/v1alpha1/linodemachine_types.go

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,38 +80,28 @@ type LinodeMachineSpec struct {
8080
// InstanceMetadataOptions defines metadata of instance
8181
type InstanceMetadataOptions struct {
8282
// UserData expects a Base64-encoded string
83-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
8483
UserData string `json:"userData,omitempty"`
8584
}
8685

8786
// InstanceConfigInterfaceCreateOptions defines network interface config
8887
type InstanceConfigInterfaceCreateOptions struct {
89-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
9088
IPAMAddress string `json:"ipamAddress,omitempty"`
9189
// +kubebuilder:validation:MinLength=3
9290
// +kubebuilder:validation:MaxLength=63
93-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
9491
// +optional
95-
Label string `json:"label,omitempty"`
96-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
92+
Label string `json:"label,omitempty"`
9793
Purpose linodego.ConfigInterfacePurpose `json:"purpose,omitempty"`
98-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
99-
Primary bool `json:"primary,omitempty"`
100-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
94+
Primary bool `json:"primary,omitempty"`
10195
// +optional
10296
SubnetID *int `json:"subnetId,omitempty"`
103-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
10497
// +optional
105-
IPv4 *VPCIPv4 `json:"ipv4,omitempty"`
106-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
98+
IPv4 *VPCIPv4 `json:"ipv4,omitempty"`
10799
IPRanges []string `json:"ipRanges,omitempty"`
108100
}
109101

110102
// VPCIPv4 defines VPC IPV4 settings
111103
type VPCIPv4 struct {
112-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
113-
VPC string `json:"vpc,omitempty"`
114-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
104+
VPC string `json:"vpc,omitempty"`
115105
NAT1To1 string `json:"nat1to1,omitempty"`
116106
}
117107

api/v1alpha1/linodevpc_types.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,8 @@ type LinodeVPCSpec struct {
4747
type VPCSubnetCreateOptions struct {
4848
// +kubebuilder:validation:MinLength=3
4949
// +kubebuilder:validation:MaxLength=63
50-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
5150
// +optional
5251
Label string `json:"label,omitempty"`
53-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
5452
// +optional
5553
IPv4 string `json:"ipv4,omitempty"`
5654
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,73 @@ spec:
7474
region:
7575
description: The Linode Region the LinodeCluster lives in.
7676
type: string
77+
vpcRef:
78+
description: "ObjectReference contains enough information
79+
to let you inspect or modify the referred object. --- New
80+
uses of this type are discouraged because of difficulty
81+
describing its usage when embedded in APIs. 1. Ignored fields.
82+
\ It includes many fields which are not generally honored.
83+
\ For instance, ResourceVersion and FieldPath are both very
84+
rarely valid in actual usage. 2. Invalid usage help. It
85+
is impossible to add specific help for individual usage.
86+
\ In most embedded usages, there are particular restrictions
87+
like, \"must refer only to types A and B\" or \"UID not
88+
honored\" or \"name must be restricted\". Those cannot be
89+
well described when embedded. 3. Inconsistent validation.
90+
\ Because the usages are different, the validation rules
91+
are different by usage, which makes it hard for users to
92+
predict what will happen. 4. The fields are both imprecise
93+
and overly precise. Kind is not a precise mapping to a
94+
URL. This can produce ambiguity during interpretation and
95+
require a REST mapping. In most cases, the dependency is
96+
on the group,resource tuple and the version of the actual
97+
struct is irrelevant. 5. We cannot easily change it. Because
98+
this type is embedded in many locations, updates to this
99+
type will affect numerous schemas. Don't make new APIs
100+
embed an underspecified API type they do not control. \n
101+
Instead of using this type, create a locally provided and
102+
used type that is well-focused on your reference. For example,
103+
ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533
104+
."
105+
properties:
106+
apiVersion:
107+
description: API version of the referent.
108+
type: string
109+
fieldPath:
110+
description: 'If referring to a piece of an object instead
111+
of an entire object, this string should contain a valid
112+
JSON/Go field access statement, such as desiredState.manifest.containers[2].
113+
For example, if the object reference is to a container
114+
within a pod, this would take on a value like: "spec.containers{name}"
115+
(where "name" refers to the name of the container that
116+
triggered the event) or if no container name is specified
117+
"spec.containers[2]" (container with index 2 in this
118+
pod). This syntax is chosen only to have some well-defined
119+
way of referencing a part of an object. TODO: this design
120+
is not final and this field is subject to change in
121+
the future.'
122+
type: string
123+
kind:
124+
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
125+
type: string
126+
name:
127+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
128+
type: string
129+
namespace:
130+
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
131+
type: string
132+
resourceVersion:
133+
description: 'Specific resourceVersion to which this reference
134+
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
135+
type: string
136+
uid:
137+
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
138+
type: string
139+
type: object
140+
x-kubernetes-map-type: atomic
141+
x-kubernetes-validations:
142+
- message: Value is immutable
143+
rule: self == oldSelf
77144
required:
78145
- region
79146
type: object

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

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -85,55 +85,28 @@ spec:
8585
items:
8686
type: string
8787
type: array
88-
x-kubernetes-validations:
89-
- message: Value is immutable
90-
rule: self == oldSelf
9188
ipamAddress:
9289
type: string
93-
x-kubernetes-validations:
94-
- message: Value is immutable
95-
rule: self == oldSelf
9690
ipv4:
9791
description: VPCIPv4 defines VPC IPV4 settings
9892
properties:
9993
nat1to1:
10094
type: string
101-
x-kubernetes-validations:
102-
- message: Value is immutable
103-
rule: self == oldSelf
10495
vpc:
10596
type: string
106-
x-kubernetes-validations:
107-
- message: Value is immutable
108-
rule: self == oldSelf
10997
type: object
110-
x-kubernetes-validations:
111-
- message: Value is immutable
112-
rule: self == oldSelf
11398
label:
11499
maxLength: 63
115100
minLength: 3
116101
type: string
117-
x-kubernetes-validations:
118-
- message: Value is immutable
119-
rule: self == oldSelf
120102
primary:
121103
type: boolean
122-
x-kubernetes-validations:
123-
- message: Value is immutable
124-
rule: self == oldSelf
125104
purpose:
126105
description: ConfigInterfacePurpose options start with InterfacePurpose
127106
and include all known interface purpose types
128107
type: string
129-
x-kubernetes-validations:
130-
- message: Value is immutable
131-
rule: self == oldSelf
132108
subnetId:
133109
type: integer
134-
x-kubernetes-validations:
135-
- message: Value is immutable
136-
rule: self == oldSelf
137110
type: object
138111
type: array
139112
x-kubernetes-validations:
@@ -152,9 +125,6 @@ spec:
152125
userData:
153126
description: UserData expects a Base64-encoded string
154127
type: string
155-
x-kubernetes-validations:
156-
- message: Value is immutable
157-
rule: self == oldSelf
158128
type: object
159129
x-kubernetes-validations:
160130
- message: Value is immutable

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ spec:
109109
type: string
110110
type: object
111111
label:
112+
maxLength: 63
113+
minLength: 3
112114
type: string
113115
primary:
114116
type: boolean
@@ -125,6 +127,8 @@ spec:
125127
- message: Value is immutable
126128
rule: self == oldSelf
127129
label:
130+
maxLength: 63
131+
minLength: 3
128132
type: string
129133
x-kubernetes-validations:
130134
- message: Value is immutable

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,10 @@ spec:
5454
properties:
5555
ipv4:
5656
type: string
57-
x-kubernetes-validations:
58-
- message: Value is immutable
59-
rule: self == oldSelf
6057
label:
6158
maxLength: 63
6259
minLength: 3
6360
type: string
64-
x-kubernetes-validations:
65-
- message: Value is immutable
66-
rule: self == oldSelf
6761
type: object
6862
type: array
6963
x-kubernetes-validations:

controller/linodemachine_controller.go

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ var skippedMachinePhases = map[string]bool{
5454
}
5555

5656
var skippedInstanceStatuses = map[linodego.InstanceStatus]bool{
57-
linodego.InstanceOffline: true,
5857
linodego.InstanceShuttingDown: true,
5958
linodego.InstanceDeleting: true,
6059
}
6160

6261
var requeueInstanceStatuses = map[linodego.InstanceStatus]bool{
62+
linodego.InstanceOffline: true,
6363
linodego.InstanceBooting: true,
6464
linodego.InstanceRebooting: true,
6565
linodego.InstanceProvisioning: true,
@@ -154,7 +154,7 @@ func (r *LinodeMachineReconciler) Reconcile(ctx context.Context, req ctrl.Reques
154154
Name: cluster.Spec.InfrastructureRef.Name,
155155
}
156156

157-
if err := r.Client.Get(ctx, linodeClusterKey, linodeCluster); err != nil {
157+
if err = r.Client.Get(ctx, linodeClusterKey, linodeCluster); err != nil {
158158
log.Error(err, "Failed to fetch Linode cluster")
159159

160160
return ctrl.Result{}, client.IgnoreNotFound(err)
@@ -248,6 +248,8 @@ func (r *LinodeMachineReconciler) reconcile(
248248
}
249249

250250
func (r *LinodeMachineReconciler) reconcileCreate(ctx context.Context, machineScope *scope.MachineScope, logger logr.Logger) (*linodego.Instance, error) {
251+
logger.Info("creating machine")
252+
251253
tags := []string{string(machineScope.LinodeCluster.UID), string(machineScope.LinodeMachine.UID)}
252254

253255
linodeInstances, err := machineScope.LinodeClient.ListInstances(ctx, linodego.NewListOptions(1, util.CreateLinodeAPIFilter("", tags)))
@@ -327,21 +329,20 @@ func (r *LinodeMachineReconciler) reconcileCreate(ctx context.Context, machineSc
327329
}
328330

329331
func (r *LinodeMachineReconciler) reconcileUpdate(ctx context.Context, logger logr.Logger, machineScope *scope.MachineScope) (res reconcile.Result, linodeInstance *linodego.Instance, err error) {
330-
if machineScope.LinodeMachine.Spec.InstanceID == nil {
331-
err = errors.New("missing instance ID")
332-
333-
return
334-
}
332+
logger.Info("updating machine")
335333

336334
res = ctrl.Result{}
337335

338-
if linodeInstance, err = machineScope.LinodeClient.GetInstance(ctx, *machineScope.LinodeMachine.Spec.InstanceID); err != nil {
339-
logger.Error(err, "Failed to get Linode machine instance")
336+
if machineScope.LinodeMachine.Spec.InstanceID == nil {
337+
return res, nil, errors.New("missing instance ID")
338+
}
340339

341-
// Not found is not an error
342-
apiErr := linodego.Error{Code: http.StatusNotFound}
343-
if apiErr.Is(err) {
344-
err = nil
340+
if linodeInstance, err = machineScope.LinodeClient.GetInstance(ctx, *machineScope.LinodeMachine.Spec.InstanceID); err != nil {
341+
err = util.IgnoreLinodeAPIError(err, http.StatusNotFound)
342+
if err != nil {
343+
logger.Error(err, "Failed to get Linode machine instance")
344+
} else {
345+
logger.Info("Instance not found, let's create a new one")
345346

346347
// Create new machine
347348
machineScope.LinodeMachine.Spec.ProviderID = nil
@@ -350,44 +351,46 @@ func (r *LinodeMachineReconciler) reconcileUpdate(ctx context.Context, logger lo
350351
conditions.MarkFalse(machineScope.LinodeMachine, clusterv1.ReadyCondition, string("missing"), clusterv1.ConditionSeverityWarning, "instance not found")
351352
}
352353

353-
return
354+
return res, linodeInstance, err
354355
}
355356

356357
if _, ok := requeueInstanceStatuses[linodeInstance.Status]; ok {
357358
if linodeInstance.Updated.Add(reconciler.DefaultMachineControllerWaitForRunningTimeout).After(time.Now()) {
358359
logger.Info("Instance has one operaton running, re-queuing reconciliation", "status", linodeInstance.Status)
359360

360-
res = ctrl.Result{RequeueAfter: reconciler.DefaultMachineControllerWaitForRunningDelay}
361-
} else {
362-
logger.Info("Instance has one operaton long running, skipping reconciliation", "status", linodeInstance.Status)
361+
return ctrl.Result{RequeueAfter: reconciler.DefaultMachineControllerWaitForRunningDelay}, linodeInstance, nil
363362
}
364363

365-
return
364+
logger.Info("Instance has one operaton long running, skipping reconciliation", "status", linodeInstance.Status)
365+
366+
conditions.MarkFalse(machineScope.LinodeMachine, clusterv1.ReadyCondition, string(linodeInstance.Status), clusterv1.ConditionSeverityInfo, "skipped due to long running operation")
367+
368+
return res, linodeInstance, nil
366369
} else if _, ok := skippedInstanceStatuses[linodeInstance.Status]; ok || linodeInstance.Status != linodego.InstanceRunning {
367370
logger.Info("Instance has incompatible status, skipping reconciliation", "status", linodeInstance.Status)
368371

369372
conditions.MarkFalse(machineScope.LinodeMachine, clusterv1.ReadyCondition, string(linodeInstance.Status), clusterv1.ConditionSeverityInfo, "incompatible status")
370373

371-
return
374+
return res, linodeInstance, nil
372375
}
373376

377+
machineScope.LinodeMachine.Status.Ready = true
378+
374379
conditions.MarkTrue(machineScope.LinodeMachine, clusterv1.ReadyCondition)
375380

376381
r.Recorder.Event(machineScope.LinodeMachine, corev1.EventTypeNormal, string(clusterv1.ReadyCondition), "instance is running")
377382

378-
return
383+
return res, linodeInstance, nil
379384
}
380385

381386
func (r *LinodeMachineReconciler) reconcileDelete(ctx context.Context, logger logr.Logger, machineScope *scope.MachineScope) error {
382387
logger.Info("deleting machine")
383388

384389
if machineScope.LinodeMachine.Spec.InstanceID != nil {
385390
if err := machineScope.LinodeClient.DeleteInstance(ctx, *machineScope.LinodeMachine.Spec.InstanceID); err != nil {
386-
logger.Info("Failed to delete Linode machine instance")
391+
if util.IgnoreLinodeAPIError(err, http.StatusNotFound) != nil {
392+
logger.Error(err, "Failed to delete Linode machine instance")
387393

388-
// Not found is not an error
389-
apiErr := linodego.Error{Code: http.StatusNotFound}
390-
if !apiErr.Is(err) {
391394
return err
392395
}
393396
}

0 commit comments

Comments
 (0)