@@ -17,12 +17,13 @@ limitations under the License.
17
17
package v1alpha4
18
18
19
19
import (
20
+ "fmt"
20
21
"reflect"
21
22
22
- "github.com/pkg/errors"
23
23
apierrors "k8s.io/apimachinery/pkg/api/errors"
24
24
"k8s.io/apimachinery/pkg/runtime"
25
25
"k8s.io/apimachinery/pkg/util/validation/field"
26
+ clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
26
27
"sigs.k8s.io/controller-runtime/pkg/builder"
27
28
logf "sigs.k8s.io/controller-runtime/pkg/log"
28
29
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -65,40 +66,58 @@ func (r *OpenStackCluster) ValidateCreate() error {
65
66
}
66
67
67
68
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
68
- func (r * OpenStackCluster ) ValidateUpdate (old runtime.Object ) error {
69
+ func (r * OpenStackCluster ) ValidateUpdate (oldRaw runtime.Object ) error {
69
70
var allErrs field.ErrorList
71
+ old , ok := oldRaw .(* OpenStackCluster )
72
+ if ! ok {
73
+ return apierrors .NewBadRequest (fmt .Sprintf ("expected an OpenStackCluster but got a %T" , oldRaw ))
74
+ }
70
75
71
- newOpenStackCluster , err := runtime . DefaultUnstructuredConverter . ToUnstructured ( r )
72
- if err != nil {
73
- return apierrors . NewInvalid ( GroupVersion . WithKind ( "OpenStackCluster" ). GroupKind (), r . Name , field. ErrorList {
74
- field . InternalError ( nil , errors . Wrap ( err , "failed to convert new OpenStackCluster to unstructured object" ) ),
75
- } )
76
+ if r . Spec . IdentityRef != nil && r . Spec . IdentityRef . Kind != defaultIdentityRefKind {
77
+ allErrs = append ( allErrs ,
78
+ field . Invalid ( field . NewPath ( "spec" , "identityRef" , "kind" ),
79
+ r . Spec . IdentityRef , "must be a Secret" ),
80
+ )
76
81
}
77
- oldOpenStackCluster , err := runtime . DefaultUnstructuredConverter . ToUnstructured ( old )
78
- if err != nil {
79
- return apierrors . NewInvalid ( GroupVersion . WithKind ( "OpenStackCluster" ). GroupKind (), r . Name , field. ErrorList {
80
- field . InternalError ( nil , errors . Wrap ( err , "failed to convert old OpenStackCluster to unstructured object" )),
81
- })
82
+
83
+ // Allow changes to Spec.IdentityRef.Name.
84
+ if old . Spec . IdentityRef != nil && r . Spec . IdentityRef != nil {
85
+ old . Spec . IdentityRef . Name = ""
86
+ r . Spec . IdentityRef . Name = ""
82
87
}
83
88
84
- if r .Spec .IdentityRef != nil && r .Spec .IdentityRef .Kind != defaultIdentityRefKind {
85
- allErrs = append (allErrs , field .Forbidden (field .NewPath ("spec" , "identityRef" , "kind" ), "must be a Secret" ))
89
+ // Allow changes to Spec.IdentityRef if it was unset.
90
+ if old .Spec .IdentityRef == nil && r .Spec .IdentityRef != nil {
91
+ old .Spec .IdentityRef = & OpenStackIdentityReference {}
92
+ r .Spec .IdentityRef = & OpenStackIdentityReference {}
86
93
}
87
94
88
- newOpenStackClusterSpec := newOpenStackCluster ["spec" ].(map [string ]interface {})
89
- oldOpenStackClusterSpec := oldOpenStackCluster ["spec" ].(map [string ]interface {})
95
+ if old .Spec .IdentityRef != nil && r .Spec .IdentityRef == nil {
96
+ allErrs = append (allErrs ,
97
+ field .Invalid (field .NewPath ("spec" , "identityRef" ),
98
+ r .Spec .IdentityRef , "field cannot be set to nil" ),
99
+ )
100
+ }
101
+
102
+ // Allow change only for the first time.
103
+ if old .Spec .ControlPlaneEndpoint .Host == "" {
104
+ old .Spec .ControlPlaneEndpoint = clusterv1.APIEndpoint {}
105
+ r .Spec .ControlPlaneEndpoint = clusterv1.APIEndpoint {}
106
+ }
90
107
91
- // get controlPlaneEndpoint, something like {"host":"", "port":""}
92
- cpe := oldOpenStackClusterSpec ["controlPlaneEndpoint" ].(map [string ]interface {})
108
+ // Allow changes to the bastion spec only if no bastion host is deployed (i.e. Spec.Bastion.Enabled=false).
109
+ if old .Status .Bastion == nil {
110
+ old .Spec .Bastion = & Bastion {}
111
+ r .Spec .Bastion = & Bastion {}
112
+ }
93
113
94
- // allow change only for the first time
95
- host , ok := cpe ["host" ].(string )
96
- if ok && len (host ) == 0 {
97
- delete (oldOpenStackClusterSpec , "controlPlaneEndpoint" )
98
- delete (newOpenStackClusterSpec , "controlPlaneEndpoint" )
114
+ // Allow toggling the bastion enabled flag.
115
+ if old .Spec .Bastion != nil && r .Spec .Bastion != nil {
116
+ old .Spec .Bastion .Enabled = true
117
+ r .Spec .Bastion .Enabled = true
99
118
}
100
119
101
- if ! reflect .DeepEqual (oldOpenStackClusterSpec , newOpenStackClusterSpec ) {
120
+ if ! reflect .DeepEqual (old . Spec , r . Spec ) {
102
121
allErrs = append (allErrs , field .Forbidden (field .NewPath ("spec" ), "cannot be modified" ))
103
122
}
104
123
0 commit comments