Skip to content

Commit c0196ef

Browse files
committed
OSASINFRA-4029: loadbalancer: add LoadBalancer controller
Add support for OpenStack Octavia Load Balancer resources. This includes: - LoadBalancer CRD with support for VIP subnet/network/port references - Controller with create, update, delete, and import capabilities - Status reporting with provisioning and operating status - Dependency resolution for Subnet, Network, Port, and Project references - Kuttl tests for create, update, import, and dependency scenarios Closes #619
1 parent 4e2b80a commit c0196ef

File tree

77 files changed

+4070
-446
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+4070
-446
lines changed

PROJECT

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ resources:
6464
kind: KeyPair
6565
path: github.com/k-orc/openstack-resource-controller/api/v1alpha1
6666
version: v1alpha1
67+
- api:
68+
crdVersion: v1
69+
namespaced: true
70+
domain: k-orc.cloud
71+
group: openstack
72+
kind: LoadBalancer
73+
path: github.com/k-orc/openstack-resource-controller/api/v1alpha1
74+
version: v1alpha1
6775
- api:
6876
crdVersion: v1
6977
namespaced: true

api/v1alpha1/loadbalancer_types.go

Lines changed: 148 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,21 @@ limitations under the License.
1616

1717
package v1alpha1
1818

19+
// Octavia provisioning status values
20+
const (
21+
LoadbalancerProvisioningStatusActive = "ACTIVE"
22+
LoadbalancerProvisioningStatusError = "ERROR"
23+
LoadbalancerProvisioningStatusPendingCreate = "PENDING_CREATE"
24+
LoadbalancerProvisioningStatusPendingUpdate = "PENDING_UPDATE"
25+
LoadbalancerProvisioningStatusPendingDelete = "PENDING_DELETE"
26+
)
27+
28+
// +kubebuilder:validation:MinLength:=1
29+
// +kubebuilder:validation:MaxLength:=255
30+
type LoadBalancerTag string
31+
1932
// LoadBalancerResourceSpec contains the desired state of the resource.
33+
// +kubebuilder:validation:XValidation:rule="has(self.vipSubnetRef) || has(self.vipNetworkRef) || has(self.vipPortRef)",message="at least one of vipSubnetRef, vipNetworkRef, or vipPortRef must be specified"
2034
type LoadBalancerResourceSpec struct {
2135
// name will be the name of the created resource. If not specified, the
2236
// name of the ORC object will be used.
@@ -29,20 +43,22 @@ type LoadBalancerResourceSpec struct {
2943
// +optional
3044
Description *string `json:"description,omitempty"`
3145

32-
// subnetRef is a reference to the ORC Subnet which this resource is associated with.
46+
// vipSubnetRef is the subnet on which to allocate the load balancer's address.
3347
// +optional
34-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="subnetRef is immutable"
35-
SubnetRef *KubernetesNameRef `json:"subnetRef,omitempty"`
48+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="vipSubnetRef is immutable"
49+
VIPSubnetRef *KubernetesNameRef `json:"vipSubnetRef,omitempty"`
3650

37-
// networkRef is a reference to the ORC Network which this resource is associated with.
51+
// vipNetworkRef is the network on which to allocate the load balancer's address.
3852
// +optional
39-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="networkRef is immutable"
40-
NetworkRef *KubernetesNameRef `json:"networkRef,omitempty"`
53+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="vipNetworkRef is immutable"
54+
VIPNetworkRef *KubernetesNameRef `json:"vipNetworkRef,omitempty"`
4155

42-
// portRef is a reference to the ORC Port which this resource is associated with.
56+
// vipPortRef is a reference to a neutron port to use for the VIP. If the port
57+
// has more than one subnet you must specify either vipSubnetRef or vipAddress
58+
// to clarify which address should be used for the VIP.
4359
// +optional
44-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="portRef is immutable"
45-
PortRef *KubernetesNameRef `json:"portRef,omitempty"`
60+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="vipPortRef is immutable"
61+
VIPPortRef *KubernetesNameRef `json:"vipPortRef,omitempty"`
4662

4763
// flavorRef is a reference to the ORC Flavor which this resource is associated with.
4864
// +optional
@@ -54,13 +70,33 @@ type LoadBalancerResourceSpec struct {
5470
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="projectRef is immutable"
5571
ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"`
5672

57-
// TODO(scaffolding): Add more types.
58-
// To see what is supported, you can take inspiration from the CreateOpts structure from
59-
// github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers
60-
//
61-
// Until you have implemented mutability for the field, you must add a CEL validation
62-
// preventing the field being modified:
63-
// `// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="<fieldname> is immutable"`
73+
// adminStateUp is the administrative state of the load balancer, which is up (true) or down (false)
74+
// +optional
75+
AdminStateUp *bool `json:"adminStateUp,omitempty"`
76+
77+
// availabilityZone is the availability zone in which to create the load balancer.
78+
// +kubebuilder:validation:MaxLength=255
79+
// +optional
80+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="availabilityZone is immutable"
81+
AvailabilityZone string `json:"availabilityZone,omitempty"`
82+
83+
// provider is the name of the load balancer provider.
84+
// +kubebuilder:validation:MaxLength=255
85+
// +optional
86+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="provider is immutable"
87+
Provider string `json:"provider,omitempty"`
88+
89+
// vipAddress is the specific IP address to use for the VIP (optional).
90+
// If not specified, one is allocated automatically from the subnet.
91+
// +optional
92+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="vipAddress is immutable"
93+
VIPAddress *IPvAny `json:"vipAddress,omitempty"`
94+
95+
// tags is a list of tags which will be applied to the load balancer.
96+
// +kubebuilder:validation:MaxItems:=64
97+
// +listType=set
98+
// +optional
99+
Tags []LoadBalancerTag `json:"tags,omitempty"`
64100
}
65101

66102
// LoadBalancerFilter defines an existing resource by its properties
@@ -76,25 +112,66 @@ type LoadBalancerFilter struct {
76112
// +optional
77113
Description *string `json:"description,omitempty"`
78114

79-
// vipNetworkRef is a reference to the ORC VipNetwork which this resource is associated with.
115+
// projectRef is a reference to the ORC Project this resource is associated with.
116+
// Typically, only used by admin.
117+
// +optional
118+
ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"`
119+
120+
// vipSubnetRef filters by the subnet on which the load balancer's address is allocated.
80121
// +optional
81-
VipNetworkRef *KubernetesNameRef `json:"vipNetworkRef,omitempty"`
122+
VIPSubnetRef *KubernetesNameRef `json:"vipSubnetRef,omitempty"`
82123

83-
// projectRef is a reference to the ORC Project which this resource is associated with.
124+
// vipNetworkRef filters by the network on which the load balancer's address is allocated.
84125
// +optional
85-
ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"`
126+
VIPNetworkRef *KubernetesNameRef `json:"vipNetworkRef,omitempty"`
127+
128+
// vipPortRef filters by the neutron port used for the VIP.
129+
// +optional
130+
VIPPortRef *KubernetesNameRef `json:"vipPortRef,omitempty"`
86131

87-
// vipSubnetRef is a reference to the ORC VipSubnet which this resource is associated with.
132+
// availabilityZone is the availability zone in which to create the load balancer.
133+
// +kubebuilder:validation:MaxLength=255
88134
// +optional
89-
VipSubnetRef *KubernetesNameRef `json:"vipSubnetRef,omitempty"`
135+
AvailabilityZone string `json:"availabilityZone,omitempty"`
90136

91-
// vipPortRef is a reference to the ORC VipPort which this resource is associated with.
137+
// provider filters by the name of the load balancer provider.
138+
// +kubebuilder:validation:MaxLength=255
92139
// +optional
93-
VipPortRef *KubernetesNameRef `json:"vipPortRef,omitempty"`
140+
Provider string `json:"provider,omitempty"`
94141

95-
// TODO(scaffolding): Add more types.
96-
// To see what is supported, you can take inspiration from the ListOpts structure from
97-
// github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers
142+
// vipAddress filters by the IP address of the load balancer's VIP.
143+
// +kubebuilder:validation:MaxLength=64
144+
// +optional
145+
VIPAddress string `json:"vipAddress,omitempty"`
146+
147+
// tags is a list of tags to filter by. If specified, the resource must
148+
// have all of the tags specified to be included in the result.
149+
// +listType=set
150+
// +optional
151+
// +kubebuilder:validation:MaxItems:=64
152+
Tags []LoadBalancerTag `json:"tags,omitempty"`
153+
154+
// tagsAny is a list of tags to filter by. If specified, the resource
155+
// must have at least one of the tags specified to be included in the
156+
// result.
157+
// +listType=set
158+
// +optional
159+
// +kubebuilder:validation:MaxItems:=64
160+
TagsAny []LoadBalancerTag `json:"tagsAny,omitempty"`
161+
162+
// notTags is a list of tags to filter by. If specified, resources which
163+
// contain all of the given tags will be excluded from the result.
164+
// +listType=set
165+
// +optional
166+
// +kubebuilder:validation:MaxItems:=64
167+
NotTags []LoadBalancerTag `json:"notTags,omitempty"`
168+
169+
// notTagsAny is a list of tags to filter by. If specified, resources
170+
// which contain any of the given tags will be excluded from the result.
171+
// +listType=set
172+
// +optional
173+
// +kubebuilder:validation:MaxItems:=64
174+
NotTagsAny []LoadBalancerTag `json:"notTagsAny,omitempty"`
98175
}
99176

100177
// LoadBalancerResourceStatus represents the observed state of the resource.
@@ -109,20 +186,20 @@ type LoadBalancerResourceStatus struct {
109186
// +optional
110187
Description string `json:"description,omitempty"`
111188

112-
// subnetID is the ID of the Subnet to which the resource is associated.
189+
// vipSubnetID is the ID of the Subnet to which the resource is associated.
113190
// +kubebuilder:validation:MaxLength=1024
114191
// +optional
115-
SubnetID string `json:"subnetID,omitempty"`
192+
VIPSubnetID string `json:"vipSubnetID,omitempty"`
116193

117-
// networkID is the ID of the Network to which the resource is associated.
194+
// vipNetworkID is the ID of the Network to which the resource is associated.
118195
// +kubebuilder:validation:MaxLength=1024
119196
// +optional
120-
NetworkID string `json:"networkID,omitempty"`
197+
VIPNetworkID string `json:"vipNetworkID,omitempty"`
121198

122-
// portID is the ID of the Port to which the resource is associated.
199+
// vipPortID is the ID of the Port to which the resource is associated.
123200
// +kubebuilder:validation:MaxLength=1024
124201
// +optional
125-
PortID string `json:"portID,omitempty"`
202+
VIPPortID string `json:"vipPortID,omitempty"`
126203

127204
// flavorID is the ID of the Flavor to which the resource is associated.
128205
// +kubebuilder:validation:MaxLength=1024
@@ -134,7 +211,42 @@ type LoadBalancerResourceStatus struct {
134211
// +optional
135212
ProjectID string `json:"projectID,omitempty"`
136213

137-
// TODO(scaffolding): Add more types.
138-
// To see what is supported, you can take inspiration from the LoadBalancer structure from
139-
// github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers
214+
// adminStateUp is the administrative state of the load balancer,
215+
// which is up (true) or down (false).
216+
// +optional
217+
AdminStateUp *bool `json:"adminStateUp,omitempty"`
218+
219+
// tags is the list of tags on the resource.
220+
// +listType=atomic
221+
// +optional
222+
// +kubebuilder:validation:MaxItems:=64
223+
// +kubebuilder:validation:items:MaxLength=255
224+
Tags []string `json:"tags,omitempty"`
225+
226+
// availabilityZone is the availability zone where the load balancer is located.
227+
// +kubebuilder:validation:MaxLength=1024
228+
// +optional
229+
AvailabilityZone string `json:"availabilityZone,omitempty"`
230+
231+
// provisioningStatus is the provisioning status of the load balancer.
232+
// This value is ACTIVE, PENDING_CREATE or ERROR.
233+
// +kubebuilder:validation:MaxLength=1024
234+
// +optional
235+
ProvisioningStatus string `json:"provisioningStatus,omitempty"`
236+
237+
// operatingStatus is the operating status of the load balancer,
238+
// such as ONLINE or OFFLINE.
239+
// +kubebuilder:validation:MaxLength=1024
240+
// +optional
241+
OperatingStatus string `json:"operatingStatus,omitempty"`
242+
243+
// provider is the name of the load balancer provider.
244+
// +kubebuilder:validation:MaxLength=1024
245+
// +optional
246+
Provider string `json:"provider,omitempty"`
247+
248+
// vipAddress is the IP address of the load balancer's VIP.
249+
// +optional
250+
// +kubebuilder:validation:MaxLength=64
251+
VIPAddress string `json:"vipAddress,omitempty"`
140252
}

0 commit comments

Comments
 (0)