From a9e58b3a1ae0d9b62678fe668b6faf73321be0ee Mon Sep 17 00:00:00 2001 From: rabi Date: Wed, 11 Sep 2024 10:05:17 +0530 Subject: [PATCH] Add ServiceNetwork attribute to networks in netconfig This would allow us to identify the ctlplane network when using custom network and also generate inventory using the ServiceNetwork. Signed-off-by: rabi --- .gitignore | 1 + apis/bases/network.openstack.org_ipsets.yaml | 5 +++ .../network.openstack.org_netconfigs.yaml | 4 +++ apis/network/v1beta1/ipset_types.go | 3 ++ apis/network/v1beta1/netconfig_types.go | 4 +++ apis/network/v1beta1/netconfig_webhook.go | 9 ++--- .../bases/network.openstack.org_ipsets.yaml | 5 +++ .../network.openstack.org_netconfigs.yaml | 4 +++ .../infra-operator.clusterserviceversion.yaml | 9 +++++ controllers/network/ipset_controller.go | 34 ++++++++++++++----- tests/functional/base_test.go | 14 ++++++++ tests/functional/ipset_controller_test.go | 15 ++++++-- 12 files changed, 92 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index bcf042e8..4fcb226a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ Dockerfile.cross bundle bundle.Dockerfile +config/manager/kustomization.yaml # Test binary, build with `go test -c` *.test diff --git a/apis/bases/network.openstack.org_ipsets.yaml b/apis/bases/network.openstack.org_ipsets.yaml index 503c946f..1d6b48fc 100644 --- a/apis/bases/network.openstack.org_ipsets.yaml +++ b/apis/bases/network.openstack.org_ipsets.yaml @@ -180,6 +180,10 @@ spec: - nexthop type: object type: array + serviceNetwork: + description: ServiceNetwork mapping + pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ + type: string subnet: description: Subnet name pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ @@ -191,6 +195,7 @@ spec: - address - dnsDomain - network + - serviceNetwork - subnet type: object type: array diff --git a/apis/bases/network.openstack.org_netconfigs.yaml b/apis/bases/network.openstack.org_netconfigs.yaml index 4d43d8c5..125f8ce9 100644 --- a/apis/bases/network.openstack.org_netconfigs.yaml +++ b/apis/bases/network.openstack.org_netconfigs.yaml @@ -55,6 +55,10 @@ spec: ... pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ type: string + serviceNetwork: + description: Service network mapping + pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ + type: string subnets: description: Subnets of the network items: diff --git a/apis/network/v1beta1/ipset_types.go b/apis/network/v1beta1/ipset_types.go index 15ade7fa..618d0b6e 100644 --- a/apis/network/v1beta1/ipset_types.go +++ b/apis/network/v1beta1/ipset_types.go @@ -82,6 +82,9 @@ type IPSetReservation struct { // DNSDomain of the subnet DNSDomain string `json:"dnsDomain"` + + // ServiceNetwork mapping + ServiceNetwork NetNameStr `json:"serviceNetwork"` } // IPSetStatus defines the observed state of IPSet diff --git a/apis/network/v1beta1/netconfig_types.go b/apis/network/v1beta1/netconfig_types.go index 41697ad0..9c88e963 100644 --- a/apis/network/v1beta1/netconfig_types.go +++ b/apis/network/v1beta1/netconfig_types.go @@ -46,6 +46,10 @@ type Network struct { // +kubebuilder:validation:Required // Subnets of the network Subnets []Subnet `json:"subnets"` + + // +kubebuilder:validation:optional + // Service network mapping + ServiceNetwork NetNameStr `json:"serviceNetwork,omitempty"` } // Subnet definition diff --git a/apis/network/v1beta1/netconfig_webhook.go b/apis/network/v1beta1/netconfig_webhook.go index 7371fffa..26e9aa71 100644 --- a/apis/network/v1beta1/netconfig_webhook.go +++ b/apis/network/v1beta1/netconfig_webhook.go @@ -51,9 +51,12 @@ var _ webhook.Defaulter = &NetConfig{} // Default implements webhook.Defaulter so a webhook will be registered for the type func (r *NetConfig) Default() { - netconfiglog.Info("default", "name", r.Name) + for _, net := range r.Spec.Networks { + if net.ServiceNetwork == "" { + net.ServiceNetwork = net.Name + } + } - // TODO(user): fill in your defaulting logic. } //+kubebuilder:webhook:path=/validate-network-openstack-org-v1beta1-netconfig,mutating=false,failurePolicy=fail,sideEffects=None,groups=network.openstack.org,resources=netconfigs,verbs=create;update;delete,versions=v1beta1,name=vnetconfig.kb.io,admissionReviewVersions=v1 @@ -146,7 +149,6 @@ func valiateNetworks( allErrs := field.ErrorList{} netNames := map[string]field.Path{} netCIDR := map[string]field.Path{} - for netIdx, _net := range networks { path := path.Child("networks").Index(netIdx) @@ -172,7 +174,6 @@ func valiateNetworks( } } } - return allErrs } diff --git a/config/crd/bases/network.openstack.org_ipsets.yaml b/config/crd/bases/network.openstack.org_ipsets.yaml index 503c946f..1d6b48fc 100644 --- a/config/crd/bases/network.openstack.org_ipsets.yaml +++ b/config/crd/bases/network.openstack.org_ipsets.yaml @@ -180,6 +180,10 @@ spec: - nexthop type: object type: array + serviceNetwork: + description: ServiceNetwork mapping + pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ + type: string subnet: description: Subnet name pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ @@ -191,6 +195,7 @@ spec: - address - dnsDomain - network + - serviceNetwork - subnet type: object type: array diff --git a/config/crd/bases/network.openstack.org_netconfigs.yaml b/config/crd/bases/network.openstack.org_netconfigs.yaml index 4d43d8c5..125f8ce9 100644 --- a/config/crd/bases/network.openstack.org_netconfigs.yaml +++ b/config/crd/bases/network.openstack.org_netconfigs.yaml @@ -55,6 +55,10 @@ spec: ... pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ type: string + serviceNetwork: + description: Service network mapping + pattern: ^[a-zA-Z0-9][a-zA-Z0-9\-_]*[a-zA-Z0-9]$ + type: string subnets: description: Subnets of the network items: diff --git a/config/manifests/bases/infra-operator.clusterserviceversion.yaml b/config/manifests/bases/infra-operator.clusterserviceversion.yaml index 71da5b78..c9a6215f 100644 --- a/config/manifests/bases/infra-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/infra-operator.clusterserviceversion.yaml @@ -28,6 +28,11 @@ spec: kind: DNSMasq name: dnsmasqs.network.openstack.org version: v1beta1 + - description: InstanceHA is the Schema for the instancehas API + displayName: Instance HA + kind: InstanceHA + name: instancehas.instanceha.openstack.org + version: v1beta1 - description: IPSet is the Schema for the ipsets API displayName: IPSet kind: IPSet @@ -51,6 +56,10 @@ spec: displayName: Redis kind: Redis name: redises.redis.openstack.org + specDescriptors: + - description: TLS settings for Redis service and internal Redis replication + displayName: TLS + path: tls version: v1beta1 - description: Reservation is the Schema for the reservations API displayName: Reservation diff --git a/controllers/network/ipset_controller.go b/controllers/network/ipset_controller.go index d621a568..0ac9ba09 100644 --- a/controllers/network/ipset_controller.go +++ b/controllers/network/ipset_controller.go @@ -20,6 +20,8 @@ import ( "context" "fmt" "net" + "sort" + "strings" corev1 "k8s.io/api/core/v1" k8s_errors "k8s.io/apimachinery/pkg/api/errors" @@ -43,6 +45,8 @@ import ( util "github.com/openstack-k8s-operators/lib-common/modules/common/util" ) +const CtlPlaneNetwork = "ctlplane" + // IPSetReconciler reconciles a IPSet object type IPSetReconciler struct { client.Client @@ -274,6 +278,13 @@ func (r *IPSetReconciler) reconcileNormal(ctx context.Context, instance *network return ctrl.Result{}, err } + // sort instance.Status.Reservations + sort.Slice(instance.Status.Reservation, func(i, j int) bool { + return (strings.EqualFold(string(instance.Status.Reservation[i].ServiceNetwork), + CtlPlaneNetwork) && !strings.EqualFold(string(instance.Status.Reservation[j].ServiceNetwork), + CtlPlaneNetwork)) + }) + instance.Status.Conditions.MarkTrue(networkv1.ReservationReadyCondition, networkv1.ReservationReadyMessage) Log.Info("IPSet is ready:", "instance", instance.Name, "ipSetRes", ipSetRes.Spec.Reservation) @@ -398,6 +409,10 @@ func (r *IPSetReconciler) ensureReservation( return nil, err } + if netDef.ServiceNetwork == "" { + netDef.ServiceNetwork = netDef.Name + } + // set net: subnet label reservationLabels = util.MergeStringMaps(reservationLabels, map[string]string{ @@ -426,15 +441,16 @@ func (r *IPSetReconciler) ensureReservation( // add IP to the reservation and IPSet status reservations reservationSpec.Reservation[string(netDef.Name)] = *ip ipsetRes := networkv1.IPSetReservation{ - Network: netDef.Name, - Subnet: subnetDef.Name, - Address: ip.Address, - MTU: netDef.MTU, - Cidr: subnetDef.Cidr, - Vlan: subnetDef.Vlan, - Gateway: subnetDef.Gateway, - Routes: subnetDef.Routes, - DNSDomain: netDef.DNSDomain, + Network: netDef.Name, + Subnet: subnetDef.Name, + Address: ip.Address, + MTU: netDef.MTU, + Cidr: subnetDef.Cidr, + Vlan: subnetDef.Vlan, + Gateway: subnetDef.Gateway, + Routes: subnetDef.Routes, + DNSDomain: netDef.DNSDomain, + ServiceNetwork: netDef.ServiceNetwork, } if ipsetNet.DefaultRoute != nil && *ipsetNet.DefaultRoute && subnetDef.Gateway != nil { ipsetRes.Gateway = subnetDef.Gateway diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go index b6d6b811..4f5aa713 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -482,6 +482,20 @@ func GetNetSpec(name string, subnets ...networkv1.Subnet) networkv1.Network { return net } +func GetNetCtlplaneSpec(name string, subnets ...networkv1.Subnet) networkv1.Network { + net := networkv1.Network{ + Name: networkv1.NetNameStr(name), + DNSDomain: fmt.Sprintf("%s.example.com", strings.ToLower(name)), + MTU: 1400, + Subnets: []networkv1.Subnet{}, + ServiceNetwork: "ctlplane", + } + + net.Subnets = append(net.Subnets, subnets...) + + return net +} + func GetDefaultNetConfigSpec() map[string]interface{} { net := GetNetSpec(net1, GetSubnet1(subnet1)) return GetNetConfigSpec(net) diff --git a/tests/functional/ipset_controller_test.go b/tests/functional/ipset_controller_test.go index ead7f066..8f79dfcf 100644 --- a/tests/functional/ipset_controller_test.go +++ b/tests/functional/ipset_controller_test.go @@ -320,7 +320,7 @@ var _ = Describe("IPSet controller", func() { BeforeEach(func() { netSpecs = []networkv1.Network{} netSpecs = append(netSpecs, GetNetSpec(net1, GetSubnet1(subnet1))) - netSpecs = append(netSpecs, GetNetSpec(net2, GetSubnet2(subnet1))) + netSpecs = append(netSpecs, GetNetCtlplaneSpec(net2, GetSubnet2(subnet1))) netSpecs = append(netSpecs, GetNetSpec(net3, GetSubnet3(subnet1))) ipSetNetworks = []networkv1.IPSetNetwork{} @@ -369,11 +369,22 @@ var _ = Describe("IPSet controller", func() { Eventually(func(g Gomega) { g.Expect(k8sClient.Get(ctx, ipSetName, instance)).Should(Succeed()) + ctlplaneNetwork := instance.Status.Reservation[0].Network + ctlplaneFound := false for i := 0; i < len(ipSetNetworks); i++ { // first assert that the instance networks are in the same order as we specified g.Expect(instance.Spec.Networks[i].Name).To(Equal(ipSetNetworks[i].Name)) // then assert that the reservation networks are in the same order - g.Expect(instance.Spec.Networks[i].Name).To(Equal(instance.Status.Reservation[i].Network)) + // other than ctlplane network being the first one. + if ipSetNetworks[i].Name == ctlplaneNetwork { + ctlplaneFound = true + continue + } + if ctlplaneFound { + g.Expect(instance.Spec.Networks[i].Name).To(Equal(instance.Status.Reservation[i].Network)) + } else { + g.Expect(instance.Spec.Networks[i].Name).To(Equal(instance.Status.Reservation[i+1].Network)) + } } g.Expect(k8sClient.Update(ctx, instance)).Should(Succeed()) }, timeout, interval).Should(Succeed())