diff --git a/broker/machinebroker/networks/networks.go b/broker/machinebroker/networks/networks.go index 633b6575b..5826ad085 100644 --- a/broker/machinebroker/networks/networks.go +++ b/broker/machinebroker/networks/networks.go @@ -227,6 +227,9 @@ func (e *Manager) emit(providerID string, network *networkingv1alpha1.Network, e w.network = network w.error = err close(w.done) + // Remove providerID from waiters map once the emit call finishes. Otherwise, we won't be able to recreate + // the network if it has been deleted (e.g. via GC when the network has been released due to the lack of consumers). + delete(e.waitersByProviderID, providerID) } func (e *Manager) GetNetwork(ctx context.Context, providerID string) (*networkingv1alpha1.Network, error) { diff --git a/broker/machinebroker/server/machine_networkinterface_attach_test.go b/broker/machinebroker/server/machine_networkinterface_attach_test.go index 1de063d9e..11d89749b 100644 --- a/broker/machinebroker/server/machine_networkinterface_attach_test.go +++ b/broker/machinebroker/server/machine_networkinterface_attach_test.go @@ -94,4 +94,97 @@ var _ = Describe("AttachNetworkInterface", func() { State: networkingv1alpha1.NetworkStateAvailable, })) }) + + It("should correctly re-create a network in case it has been removed", func(ctx SpecContext) { + By("creating a machine") + createMachineRes, err := srv.CreateMachine(ctx, &ori.CreateMachineRequest{ + Machine: &ori.Machine{ + Spec: &ori.MachineSpec{ + Power: ori.Power_POWER_ON, + Image: &ori.ImageSpec{ + Image: "example.org/foo:latest", + }, + Class: machineClass.Name, + }, + }, + }) + Expect(err).NotTo(HaveOccurred()) + machineID := createMachineRes.Machine.Metadata.Id + + By("attaching a network interface") + Expect(srv.AttachNetworkInterface(ctx, &ori.AttachNetworkInterfaceRequest{ + MachineId: machineID, + NetworkInterface: &ori.NetworkInterface{ + Name: "my-nic", + NetworkId: "network-id", + Ips: []string{"10.0.0.1"}, + }, + })).Error().NotTo(HaveOccurred()) + + By("getting the onmetal machine") + onmetalMachine := &computev1alpha1.Machine{} + onmetalMachineKey := client.ObjectKey{Namespace: ns.Name, Name: machineID} + Expect(k8sClient.Get(ctx, onmetalMachineKey, onmetalMachine)).To(Succeed()) + + By("inspecting the onmetal machine's network interfaces") + Expect(onmetalMachine.Spec.NetworkInterfaces).To(ConsistOf(MatchAllFields(Fields{ + "Name": Equal("my-nic"), + "NetworkInterfaceSource": MatchFields(IgnoreExtras, Fields{ + "NetworkInterfaceRef": PointTo(MatchAllFields(Fields{ + "Name": Not(BeEmpty()), + })), + }), + }))) + + By("getting the corresponding onmetal network interface") + nic := &networkingv1alpha1.NetworkInterface{} + nicName := onmetalMachine.Spec.NetworkInterfaces[0].NetworkInterfaceRef.Name + nicKey := client.ObjectKey{Namespace: ns.Name, Name: nicName} + Expect(k8sClient.Get(ctx, nicKey, nic)).To(Succeed()) + + By("inspecting the onmetal network interface") + Expect(nic.Spec.IPs).To(Equal([]networkingv1alpha1.IPSource{ + {Value: commonv1alpha1.MustParseNewIP("10.0.0.1")}, + })) + + By("getting the referenced onmetal network") + network := &networkingv1alpha1.Network{} + networkKey := client.ObjectKey{Namespace: ns.Name, Name: nic.Spec.NetworkRef.Name} + Expect(k8sClient.Get(ctx, networkKey, network)).To(Succeed()) + + By("inspecting the onmetal network") + Expect(network.Spec).To(Equal(networkingv1alpha1.NetworkSpec{ + ProviderID: "network-id", + })) + Expect(network.Status).To(Equal(networkingv1alpha1.NetworkStatus{ + State: networkingv1alpha1.NetworkStateAvailable, + })) + + By("detaching the network interface") + Expect(srv.DetachNetworkInterface(ctx, &ori.DetachNetworkInterfaceRequest{ + MachineId: machineID, + Name: "my-nic", + })).Error().NotTo(HaveOccurred()) + + By("deleting the network") + Expect(k8sClient.Delete(ctx, network)).To(Succeed()) + + By("re-attaching a network interface") + Expect(srv.AttachNetworkInterface(ctx, &ori.AttachNetworkInterfaceRequest{ + MachineId: machineID, + NetworkInterface: &ori.NetworkInterface{ + Name: "my-nic", + NetworkId: "network-id", + Ips: []string{"10.0.0.1"}, + }, + })).Error().NotTo(HaveOccurred()) + + By("inspecting the onmetal network again") + Expect(network.Spec).To(Equal(networkingv1alpha1.NetworkSpec{ + ProviderID: "network-id", + })) + Expect(network.Status).To(Equal(networkingv1alpha1.NetworkStatus{ + State: networkingv1alpha1.NetworkStateAvailable, + })) + }) })