Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow configuration of the subnet the LB is placed in #287

Merged
merged 2 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ yawolFloatingID: <floating-id>
# Placed in LoadBalancer.spec.infrastructure.networkID
yawolNetworkID: <network-id>

# OpenStack subnet ID in which the Load Balancer is placed.
# If not set, the subnet is chosen automatically.
#
# Placed in LoadBalancer.spec.infrastructure.subnetID
yawolSubnetID: <subnet-id>

# default value for flavor that yawol Load Balancer instances should use
# can be overridden by annotation
#
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/loadbalancer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const (
// If this is set to a different network ID than defined as default in the yawol-cloud-controller
// the default from the yawol-cloud-controller will be added to the additionalNetworks
ServiceDefaultNetworkID = "yawol.stackit.cloud/defaultNetworkID"
// ServiceDefaultSubnetID overwrites the default openstack subnet for the loadbalancer
ServiceDefaultSubnetID = "yawol.stackit.cloud/defaultSubnetID"
// ServiceSkipCloudControllerDefaultNetworkID if set to true it do not add the default network ID from
// the yawol-cloud-controller to the additionalNetworks
ServiceSkipCloudControllerDefaultNetworkID = "yawol.stackit.cloud/skipCloudControllerDefaultNetworkID"
Expand Down Expand Up @@ -245,6 +247,9 @@ type LoadBalancerDefaultNetwork struct {
FloatingNetID *string `json:"floatingNetID,omitempty"`
// NetworkID defines an openstack ID for the network.
NetworkID string `json:"networkID"`
// SubnetID defines an openstack ID for the subnet.
// +optional
SubnetID *string `json:"subnetID,omitempty"`
}

// OpenstackImageRef defines a reference to a Openstack image.
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions charts/yawol-controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ Helm chart for yawol-controller
| yawolFloatingID | string | `nil` | |
| yawolImageID | string | `nil` | |
| yawolNetworkID | string | `nil` | |
| yawolSubnetID | string | `nil` | |
| yawolOSSecretName | string | `nil` | |

Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ spec:
networkID:
description: NetworkID defines an openstack ID for the network.
type: string
subnetID:
description: SubnetID defines an openstack ID for the
subnet.
type: string
required:
- networkID
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ spec:
networkID:
description: NetworkID defines an openstack ID for the network.
type: string
subnetID:
description: SubnetID defines an openstack ID for the
subnet.
type: string
required:
- networkID
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ spec:
description: NetworkID defines an openstack ID for
the network.
type: string
subnetID:
description: SubnetID defines an openstack ID
for the subnet.
type: string
required:
- networkID
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ spec:
- name: NETWORK_ID
value: {{ .Values.yawolNetworkID }}
{{- end }}
{{- if .Values.yawolSubnetID }}
- name: SUBNET_ID
value: {{ .Values.yawolSubnetID }}
{{- end }}
{{- if .Values.yawolFlavorID }}
- name: FLAVOR_ID
value: {{ .Values.yawolFlavorID }}
Expand Down
6 changes: 6 additions & 0 deletions charts/yawol-controller/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ yawolFloatingID:
# Placed in LoadBalancer.spec.infrastructure.networkID
yawolNetworkID:

# OpenStack subnet ID in which the Load Balancer is placed.
# If not set, the subnet is chosen automatically.
#
# Placed in LoadBalancer.spec.infrastructure.subnetID
yawolSubnetID:

# default value for flavor that yawol Load Balancer instances should use
# can be overridden by annotation
#
Expand Down
8 changes: 8 additions & 0 deletions cmd/yawol-cloud-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const (
EnvFloatingNetID = "FLOATING_NET_ID"
// Openstack NetworkID for LB
EnvNetworkID = "NETWORK_ID"
// OpenStack SubnetID for LB
EnvSubnetID = "SUBNET_ID"
// Flavor Information
// one must be set
EnvFlavorID = "FLAVOR_ID"
Expand Down Expand Up @@ -301,6 +303,11 @@ func getInfrastructureDefaultsFromEnvOrDie() targetcontroller.InfrastructureDefa
panic("could not read env " + EnvNetworkID)
}

var subnetID *string
if subnetID = ptr.To(os.Getenv(EnvSubnetID)); *subnetID == "" {
subnetID = nil
}

var clusterNamespace string
if clusterNamespace = os.Getenv(EnvClusterNamespace); clusterNamespace == "" {
panic("could not read env " + EnvClusterNamespace)
Expand Down Expand Up @@ -358,6 +365,7 @@ func getInfrastructureDefaultsFromEnvOrDie() targetcontroller.InfrastructureDefa
AuthSecretName: ptr.To(authSecretName),
FloatingNetworkID: ptr.To(floatingNetworkID),
NetworkID: ptr.To(networkID),
SubnetID: subnetID,
Namespace: ptr.To(clusterNamespace),
FlavorRef: &yawolv1beta1.OpenstackFlavorRef{
FlavorID: flavorID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type InfrastructureDefaults struct {
AuthSecretName *string
FloatingNetworkID *string
NetworkID *string
SubnetID *string
Namespace *string
FlavorRef *yawolv1beta1.OpenstackFlavorRef
ImageRef *yawolv1beta1.OpenstackImageRef
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ func getDefaultNetwork(
defaultNetwork := yawolv1beta1.LoadBalancerDefaultNetwork{
FloatingNetID: infraConfig.FloatingNetworkID,
NetworkID: *infraConfig.NetworkID,
SubnetID: infraConfig.SubnetID,
}

if networkID, ok := svc.Annotations[yawolv1beta1.ServiceDefaultNetworkID]; ok {
Expand All @@ -643,6 +644,10 @@ func getDefaultNetwork(
if floatingID, ok := svc.Annotations[yawolv1beta1.ServiceFloatingNetworkID]; ok {
defaultNetwork.FloatingNetID = &floatingID
}

if subnetID, ok := svc.Annotations[yawolv1beta1.ServiceDefaultSubnetID]; ok {
defaultNetwork.SubnetID = &subnetID
}
return defaultNetwork
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2482,5 +2482,62 @@ var _ = Describe("Check loadbalancer reconcile", Serial, Ordered, func() {
return fmt.Errorf("projectID is not correctly set in infrastructure %v", lb.Spec.Infrastructure.ProjectID)
}, time.Second*5, time.Millisecond*500).Should(Succeed())
})

It("should update subnet from annotation", func() {
By("creating a service without overwritten subnet id")
service := v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "service-test34",
Namespace: "default",
},
Spec: v1.ServiceSpec{
Ports: []v1.ServicePort{
{
Name: "port1",
Protocol: v1.ProtocolTCP,
Port: 12345,
TargetPort: intstr.IntOrString{IntVal: 12345},
NodePort: 31034,
},
},
Type: "LoadBalancer",
},
}
Expect(k8sClient.Create(ctx, &service)).Should(Succeed())

By("checking that the defaultNetwork SubnetID is set")
Eventually(func() error {
err := k8sClient.Get(ctx, types.NamespacedName{Name: "default--service-test34", Namespace: "default"}, &lb)
if err != nil {
return err
}
if (testInfraDefaults.SubnetID == nil && lb.Spec.Infrastructure.DefaultNetwork.SubnetID == nil) ||
(lb.Spec.Infrastructure.DefaultNetwork.SubnetID != nil && testInfraDefaults.SubnetID != nil &&
*lb.Spec.Infrastructure.DefaultNetwork.SubnetID == *testInfraDefaults.SubnetID) {
return nil
}
return fmt.Errorf("defaultNetwork subbnetID is not correct %v", lb.Spec.Infrastructure.DefaultNetwork.SubnetID)
}, time.Second*5, time.Millisecond*500).Should(Succeed())

By("update svc to overwrite subbnetwork ID")
Expect(k8sClient.Get(ctx, client.ObjectKey{Name: service.Name, Namespace: service.Namespace}, &service)).Should(Succeed())
service.ObjectMeta.Annotations = map[string]string{
yawolv1beta1.ServiceDefaultSubnetID: "newSubnetID",
}
Expect(k8sClient.Update(ctx, &service)).Should(Succeed())

By("check if lb gets new subnet ID")
Eventually(func() error {
err := k8sClient.Get(ctx, types.NamespacedName{Name: "default--service-test34", Namespace: "default"}, &lb)
if err != nil {
return err
}
if lb.Spec.Infrastructure.DefaultNetwork.SubnetID != nil &&
*lb.Spec.Infrastructure.DefaultNetwork.SubnetID == "newSubnetID" {
return nil
}
return fmt.Errorf("defaultNetwork SubnetID is not correct %v", lb.Spec.Infrastructure.DefaultNetwork.NetworkID)
}, time.Second*5, time.Millisecond*500).Should(Succeed())
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -575,11 +575,17 @@ func (r *Reconciler) reconcilePort( //nolint: gocyclo // TODO reduce complexity
networkID = lb.Spec.Infrastructure.DefaultNetwork.NetworkID
}

var subnetID string
if lb.Spec.Infrastructure.DefaultNetwork.SubnetID != nil {
subnetID = *lb.Spec.Infrastructure.DefaultNetwork.SubnetID
}

port, err = openstackhelper.CreatePort(
ctx,
portClient,
*lb.Status.PortName,
networkID,
subnetID,
)
if err != nil {
r.Log.Info("unexpected error occurred claiming a port", "lb", req.NamespacedName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,7 @@ func getMockLB(lbNN types.NamespacedName) *LB {
DefaultNetwork: yawolv1beta1.LoadBalancerDefaultNetwork{
FloatingNetID: ptr.To("floatingnet-id"),
NetworkID: "network-id",
SubnetID: ptr.To("subnet-id"),
},
Flavor: yawolv1beta1.OpenstackFlavorRef{
FlavorID: ptr.To("flavor-id"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,11 @@ func (r *LoadBalancerMachineReconciler) reconcilePort( //nolint: gocyclo // TODO
return helper.ErrNoNetworkID
}

var subnetID string
if lbm.Spec.Infrastructure.DefaultNetwork.SubnetID != nil {
subnetID = *lbm.Spec.Infrastructure.DefaultNetwork.SubnetID
}

var portClient os.PortClient
portClient, err = osClient.PortClient(ctx)
if err != nil {
Expand Down Expand Up @@ -509,7 +514,8 @@ func (r *LoadBalancerMachineReconciler) reconcilePort( //nolint: gocyclo // TODO
ctx,
portClient,
*lbm.Status.DefaultPortName,
networkID)
networkID,
subnetID)
if err != nil {
r.Log.Info("unexpected error occurred claiming a port", "lbm", lbm.Name)
return kubernetes.SendErrorAsEvent(r.RecorderLB, err, lbm)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,60 @@ var _ = Describe("load balancer machine", Serial, Ordered, func() {
})
}) // openstack not working

Context("customizable subnetID features", func() {
BeforeEach(func() {
lbm.Spec.Infrastructure.DefaultNetwork.SubnetID = ptr.To("lb-subnetID")
})

It("should create openstack resources", func() {
lbmNN := runtimeClient.ObjectKeyFromObject(lbm)

Eventually(func(g Gomega) {
var actual yawolv1beta1.LoadBalancerMachine
g.Expect(k8sClient.Get(ctx, lbmNN, &actual)).To(Succeed())

g.Expect(actual.Status.ServerID).ToNot(BeNil())
g.Expect(actual.Status.DefaultPortID).ToNot(BeNil())

_, err := client.ServerClientObj.Get(ctx, *actual.Status.ServerID)
g.Expect(err).To(Succeed())

port, err := client.PortClientObj.Get(ctx, *actual.Status.DefaultPortID)
g.Expect(err).To(Succeed())
g.Expect(port.FixedIPs).To(HaveLen(1))

g.Expect(port.FixedIPs[0].SubnetID).To(Equal("lb-subnetID"))
}, timeout, interval).Should(Succeed())
})
}) // customizable subnetID features

Context("fallback to default subnetID", func() {
BeforeEach(func() {
lbm.Spec.Infrastructure.DefaultNetwork.SubnetID = nil // unset
})

It("should create openstack resources", func() {
lbmNN := runtimeClient.ObjectKeyFromObject(lbm)

Eventually(func(g Gomega) {
var actual yawolv1beta1.LoadBalancerMachine
g.Expect(k8sClient.Get(ctx, lbmNN, &actual)).To(Succeed())

g.Expect(actual.Status.ServerID).ToNot(BeNil())
g.Expect(actual.Status.DefaultPortID).ToNot(BeNil())

_, err := client.ServerClientObj.Get(ctx, *actual.Status.ServerID)
g.Expect(err).To(Succeed())

port, err := client.PortClientObj.Get(ctx, *actual.Status.DefaultPortID)
g.Expect(err).To(Succeed())
g.Expect(len(port.FixedIPs)).To(Equal(1))

g.Expect(port.FixedIPs[0].SubnetID).To(Equal("default-subnet-id"))
}, timeout, interval).Should(Succeed())
})
}) // fallback to default subnetID

Context("additionalNetworks features", func() {
BeforeEach(func() {
lbm.Spec.Infrastructure.AdditionalNetworks = []yawolv1beta1.LoadBalancerAdditionalNetwork{
Expand Down
6 changes: 6 additions & 0 deletions internal/helper/openstack/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ func CreatePort(
portClient openstack.PortClient,
portName string,
networkID string,
subnetID string,
) (*ports.Port, error) {
opts := ports.CreateOpts{
Name: portName,
NetworkID: networkID,
}
if subnetID != "" {
opts.FixedIPs = []ports.IP{
{SubnetID: subnetID},
}
}
port, err := portClient.Create(ctx, opts)
if err != nil {
return nil, err
Expand Down
10 changes: 9 additions & 1 deletion internal/openstack/testing/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,20 @@ func GetFakeClient() *MockClient {
},
CreateFunc: func(ctx context.Context, optsBuilder ports.CreateOptsBuilder) (*ports.Port, error) {
opts := optsBuilder.(ports.CreateOpts)
var fixedIPs []ports.IP
if opts.FixedIPs != nil {
fixedIPs = opts.FixedIPs.([]ports.IP)
}

subnetID := "default-subnet-id"
if len(fixedIPs) > 0 {
subnetID = fixedIPs[0].SubnetID
}
port := &ports.Port{
ID: getID(&client),
Name: opts.Name,
NetworkID: opts.NetworkID,
FixedIPs: []ports.IP{{IPAddress: generateIP()}},
FixedIPs: []ports.IP{{SubnetID: subnetID, IPAddress: generateIP()}},
}

if opts.SecurityGroups != nil {
Expand Down