Compare commits

...

12 Commits

Author SHA1 Message Date
b59fc563f3 rename
Some checks failed
Lint / Run on Ubuntu (push) Failing after 6s
E2E Tests / Run on Ubuntu (push) Failing after 3s
Tests / Run on Ubuntu (push) Failing after 4s
2025-06-23 23:50:53 +02:00
b444690400 Merge pull request #40 from vegardengen/39-port-forwards-should-not-log-per-default
Turn off logging for newly created portforward rules
2025-06-11 10:14:56 +02:00
bcf73d64bf Turn off logging for newly created portforward rules 2025-06-11 10:13:48 +02:00
d372e4c7a7 Merge pull request #38 from vegardengen/37-optimize-api-usage
37 optimize api usage
2025-06-04 22:12:51 +02:00
c80473d9e8 workaround for bug? 2025-06-04 22:02:48 +02:00
bcffdfede7 Change leader election 2025-06-04 20:56:52 +02:00
d7a444c8d7 Change an ID in Delete firewallgroup 2025-06-04 20:56:37 +02:00
df9926e3da Small fix on updating firewall group/deleting component of it in Unifi 2025-06-04 19:10:03 +02:00
c2ffce2d4d Do a few less updates 2025-06-04 18:29:26 +02:00
fc0bda1e7b Merge pull request #36 from vegardengen/35-fix-portforward-logic
Check if portfoward already exists, and update if needed
2025-04-22 07:34:48 +02:00
dd4df6ee07 Check if portfoward already exists, and update if needed 2025-04-22 07:33:05 +02:00
86b58cb5a9 Merge pull request #34 from vegardengen/11-create-port-forward-api
Portforward API
2025-04-21 10:37:11 +02:00
5 changed files with 59 additions and 30 deletions

View File

@@ -21,11 +21,13 @@ import (
"flag" "flag"
"os" "os"
"path/filepath" "path/filepath"
"time"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them. // to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/utils/pointer"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme" clientgoscheme "k8s.io/client-go/kubernetes/scheme"
@@ -37,10 +39,10 @@ import (
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook"
unifiv1beta1 "github.com/vegardengen/unifi-network-operator/api/v1beta1" unifiv1beta1 "gitea.engen.priv.no/klauvsteinen/unifi-network-operator/api/v1beta1"
"github.com/vegardengen/unifi-network-operator/internal/config" "gitea.engen.priv.no/klauvsteinen/unifi-network-operator/internal/config"
"github.com/vegardengen/unifi-network-operator/internal/controller" "gitea.engen.priv.no/klauvsteinen/unifi-network-operator/internal/controller"
"github.com/vegardengen/unifi-network-operator/internal/unifi" "gitea.engen.priv.no/klauvsteinen/unifi-network-operator/internal/unifi"
// +kubebuilder:scaffold:imports // +kubebuilder:scaffold:imports
) )
@@ -187,6 +189,10 @@ func main() {
HealthProbeBindAddress: probeAddr, HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection, LeaderElection: enableLeaderElection,
LeaderElectionID: "f05533b6.engen.priv.no", LeaderElectionID: "f05533b6.engen.priv.no",
LeaseDuration: pointer.Duration(30 * time.Second),
RenewDeadline: pointer.Duration(20 * time.Second),
RetryPeriod: pointer.Duration(5 * time.Second),
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
// when the Manager ends. This requires the binary to immediately end when the // when the Manager ends. This requires the binary to immediately end when the
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/vegardengen/unifi-network-operator module repository.engen.priv.no/vegardengen/unifi-network-operator
go 1.24.0 go 1.24.0

View File

@@ -372,12 +372,12 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req reconcile.R
for _, firewall_group := range firewall_groups { for _, firewall_group := range firewall_groups {
if firewall_group.Name == ipv4_name { if firewall_group.Name == ipv4_name {
if len(ipv4) == 0 { if len(ipv4) == 0 {
log.Info(fmt.Sprintf("Delete %s", ipv4_name)) log.Info(fmt.Sprintf("Delete %s: %s", ipv4_name, firewallGroup.Status.ResourcesManaged.IPV4Object.ID))
err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewall_group.ID) err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewallGroup.Status.ResourcesManaged.IPV4Object.ID)
if err != nil { if err != nil {
msg := strings.ToLower(err.Error()) msg := strings.ToLower(err.Error())
log.Info(msg) log.Info(msg)
if strings.Contains(msg, "api.err.objectreferredby") { if strings.Contains(msg, "api.err.objectreferredby") || strings.Contains(msg,"invalid character") {
log.Info("Firewall group is in use. Invoking workaround...!") log.Info("Firewall group is in use. Invoking workaround...!")
firewall_group.GroupMembers = []string{"127.0.0.1"} firewall_group.GroupMembers = []string{"127.0.0.1"}
firewall_group.Name = firewall_group.Name + "-deleted" firewall_group.Name = firewall_group.Name + "-deleted"
@@ -413,11 +413,11 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req reconcile.R
if firewall_group.Name == ipv6_name { if firewall_group.Name == ipv6_name {
if len(ipv6) == 0 { if len(ipv6) == 0 {
log.Info(fmt.Sprintf("Delete %s", ipv6_name)) log.Info(fmt.Sprintf("Delete %s", ipv6_name))
err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewall_group.ID) err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewallGroup.Status.ResourcesManaged.IPV6Object.ID)
if err != nil { if err != nil {
msg := strings.ToLower(err.Error()) msg := strings.ToLower(err.Error())
log.Info(msg) log.Info(msg)
if strings.Contains(msg, "api.err.objectreferredby") { if strings.Contains(msg, "api.err.objectreferredby") || strings.Contains(msg,"invalid character") {
log.Info("Firewall group is in use. Invoking workaround...!") log.Info("Firewall group is in use. Invoking workaround...!")
firewall_group.GroupMembers = []string{"::1"} firewall_group.GroupMembers = []string{"::1"}
firewall_group.Name = firewall_group.Name + "-deleted" firewall_group.Name = firewall_group.Name + "-deleted"
@@ -453,11 +453,11 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req reconcile.R
if firewall_group.Name == tcpports_name { if firewall_group.Name == tcpports_name {
if len(tcpports) == 0 { if len(tcpports) == 0 {
log.Info(fmt.Sprintf("Delete %s", tcpports_name)) log.Info(fmt.Sprintf("Delete %s", tcpports_name))
err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewall_group.ID) err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID)
if err != nil { if err != nil {
msg := strings.ToLower(err.Error()) msg := strings.ToLower(err.Error())
log.Info(msg) log.Info(msg)
if strings.Contains(msg, "api.err.objectreferredby") { if strings.Contains(msg, "api.err.objectreferredby") || strings.Contains(msg,"invalid character") {
log.Info("Firewall group is in use. Invoking workaround...!") log.Info("Firewall group is in use. Invoking workaround...!")
firewall_group.GroupMembers = []string{"0"} firewall_group.GroupMembers = []string{"0"}
firewall_group.Name = firewall_group.Name + "-deleted" firewall_group.Name = firewall_group.Name + "-deleted"
@@ -493,11 +493,11 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req reconcile.R
if firewall_group.Name == udpports_name { if firewall_group.Name == udpports_name {
if len(udpports) == 0 { if len(udpports) == 0 {
log.Info(fmt.Sprintf("Delete %s", udpports_name)) log.Info(fmt.Sprintf("Delete %s", udpports_name))
err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewall_group.ID) err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID)
if err != nil { if err != nil {
msg := strings.ToLower(err.Error()) msg := strings.ToLower(err.Error())
log.Info(msg) log.Info(msg)
if strings.Contains(msg, "api.err.objectreferredby") { if strings.Contains(msg, "api.err.objectreferredby") || strings.Contains(msg,"invalid character") {
log.Info("Firewall group is in use. Invoking workaround...!") log.Info("Firewall group is in use. Invoking workaround...!")
firewall_group.GroupMembers = []string{"127.0.0.1"} firewall_group.GroupMembers = []string{"127.0.0.1"}
firewall_group.Name = firewall_group.Name + "-deleted" firewall_group.Name = firewall_group.Name + "-deleted"

View File

@@ -19,6 +19,7 @@ package controller
import ( import (
"context" "context"
"fmt" "fmt"
"reflect"
"time" "time"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@@ -111,10 +112,12 @@ func (r *NetworkconfigurationReconciler) Reconcile(ctx context.Context, req ctrl
Vlan: int64(unifinetwork.VLAN), Vlan: int64(unifinetwork.VLAN),
VlanEnabled: unifinetwork.VLANEnabled, VlanEnabled: unifinetwork.VLANEnabled,
} }
networkObj.Spec = networkSpec if !reflect.DeepEqual(networkObj.Spec, networkSpec) {
err := r.Update(ctx, &networkObj) networkObj.Spec = networkSpec
if err != nil { err := r.Update(ctx, &networkObj)
return ctrl.Result{}, err if err != nil {
return ctrl.Result{}, err
}
} }
} }
} }
@@ -210,14 +213,19 @@ func (r *NetworkconfigurationReconciler) Reconcile(ctx context.Context, req ctrl
} else { } else {
for _, networkCRD := range networkCRDs.Items { for _, networkCRD := range networkCRDs.Items {
if networkCRD.Spec.Name == unifinetwork.Name { if networkCRD.Spec.Name == unifinetwork.Name {
networkCRD.Spec = networkSpec if !reflect.DeepEqual(networkCRD.Spec, networkSpec) {
} networkCRD.Spec = networkSpec
err := r.Update(ctx, &networkCRD) err := r.Update(ctx, &networkCRD)
if err != nil { if err != nil {
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err return ctrl.Result{RequeueAfter: 10 * time.Minute}, err
} }
if err = r.Status().Update(ctx, &networkCRD); err != nil { }
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err if !reflect.DeepEqual(networkCRD.Status, networkStatus) {
networkCRD.Status = networkStatus
if err = r.Status().Update(ctx, &networkCRD); err != nil {
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err
}
}
} }
} }
} }

View File

@@ -119,10 +119,25 @@ func (r *PortForwardReconciler) Reconcile(ctx context.Context, req ctrl.Request)
} }
portforwardname := "k8s-forward-" + svc.Name + "-" + port.Name portforwardname := "k8s-forward-" + svc.Name + "-" + port.Name
log.Info(fmt.Sprintf("Should handle %s", portforwardname)) log.Info(fmt.Sprintf("Should handle %s", portforwardname))
_, err := r.UnifiClient.Client.CreatePortForward(context.Background(), r.UnifiClient.SiteID, &goUnifi.PortForward{Name: portforwardname, PfwdInterface: "wan", Src: "any", Log: true, DestinationIPs: []goUnifi.PortForwardDestinationIPs{}, Enabled: true, Fwd: ip, DestinationIP: "any", Proto: "tcp", DstPort: fmt.Sprintf("%d", portMap[port.Name]), SiteID: r.UnifiClient.SiteID, FwdPort: fmt.Sprintf("%d", port.Port)}) if portforwardindex, found := portforwardnames[portforwardname]; found {
if err != nil { if portforwards[portforwardindex].DstPort == fmt.Sprintf("%d", portMap[port.Name]) && portforwards[portforwardindex].Fwd == ip && portforwards[portforwardindex].FwdPort == fmt.Sprintf("%d", port.Port) {
log.Error(err, "Portforward could not be created") log.Info("Portforward already exists and is correct")
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err } else {
log.Info("Exists, but need to update")
portforwards[portforwardindex].DstPort = fmt.Sprintf("%d", portMap[port.Name])
portforwards[portforwardindex].FwdPort = fmt.Sprintf("%d", port.Port)
portforwards[portforwardindex].Fwd = ip
if _, err := r.UnifiClient.Client.UpdatePortForward(context.Background(), r.UnifiClient.SiteID, &portforwards[portforwardindex]); err != nil {
log.Error(err, fmt.Sprintf("Failed to update portforward %s", portforwardname))
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err
}
}
} else {
_, err := r.UnifiClient.Client.CreatePortForward(context.Background(), r.UnifiClient.SiteID, &goUnifi.PortForward{Name: portforwardname, PfwdInterface: "wan", Src: "any", Log: false, DestinationIPs: []goUnifi.PortForwardDestinationIPs{}, Enabled: true, Fwd: ip, DestinationIP: "any", Proto: "tcp", DstPort: fmt.Sprintf("%d", portMap[port.Name]), SiteID: r.UnifiClient.SiteID, FwdPort: fmt.Sprintf("%d", port.Port)})
if err != nil {
log.Error(err, "Portforward could not be created")
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err
}
} }
} }