Merge pull request #5 from vegardengen/4-handle-reauthentication

Reauthentication and deleting firewall groups that are in use.
This commit is contained in:
2025-04-10 13:53:53 +02:00
committed by GitHub
3 changed files with 115 additions and 13 deletions

View File

@@ -9,9 +9,4 @@ spec:
name: Test name: Test
manualAddresses: manualAddresses:
- 192.168.1.153 - 192.168.1.153
- 192.168.1.154
- 192.168.1.155
- 2a01::3
- 2a01:0::5
- 2a01:2a01::/32
# TODO(user): Add fields here # TODO(user): Add fields here

View File

@@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"net" "net"
"reflect" "reflect"
"strings"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime"
@@ -90,6 +91,10 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req ctrl.Reques
} }
} }
} }
err := r.UnifiClient.Reauthenticate()
if err != nil {
return ctrl.Result{}, err
}
firewall_groups, err := r.UnifiClient.Client.ListFirewallGroup(context.Background(), r.UnifiClient.SiteID) firewall_groups, err := r.UnifiClient.Client.ListFirewallGroup(context.Background(), r.UnifiClient.SiteID)
if err != nil { if err != nil {
log.Error(err, "Could not list network objects") log.Error(err, "Could not list network objects")
@@ -105,8 +110,21 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req ctrl.Reques
log.Info(fmt.Sprintf("Delete %s", ipv4_name)) log.Info(fmt.Sprintf("Delete %s", ipv4_name))
err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewall_group.ID) err := r.UnifiClient.Client.DeleteFirewallGroup(context.Background(), r.UnifiClient.SiteID, firewall_group.ID)
if err != nil { if err != nil {
log.Error(err, "Could not delete firewall group") msg := strings.ToLower(err.Error())
return ctrl.Result{}, err log.Info(msg)
if strings.Contains(msg, "api.err.objectreferredby") {
log.Info("Firewall group is in use. Invoking workaround...!")
firewall_group.GroupMembers = []string{"127.0.0.1"}
firewall_group.Name = firewall_group.Name + "-deleted"
_, updateerr := r.UnifiClient.Client.UpdateFirewallGroup(context.Background(), r.UnifiClient.SiteID, &firewall_group)
if updateerr != nil {
log.Error(updateerr, "Could neither delete or rename firewall group")
return ctrl.Result{}, updateerr
}
} else {
log.Error(err, "Could not delete firewall group")
return ctrl.Result{}, err
}
} }
ipv4_done = true ipv4_done = true
} else { } else {
@@ -127,8 +145,21 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req ctrl.Reques
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, firewall_group.ID)
if err != nil { if err != nil {
log.Error(err, "Could not delete firewall group") msg := strings.ToLower(err.Error())
return ctrl.Result{}, err log.Info(msg)
if strings.Contains(msg, "api.err.objectreferredby") {
log.Info("Firewall group is in use. Invoking workaround...!")
firewall_group.GroupMembers = []string{"::1"}
firewall_group.Name = firewall_group.Name + "-deleted"
_, updateerr := r.UnifiClient.Client.UpdateFirewallGroup(context.Background(), r.UnifiClient.SiteID, &firewall_group)
if updateerr != nil {
log.Error(updateerr, "Could neither delete or rename firewall group")
return ctrl.Result{}, updateerr
}
} else {
log.Error(err, "Could not delete firewall group")
return ctrl.Result{}, err
}
} }
ipv6_done = true ipv6_done = true
} else { } else {
@@ -144,6 +175,28 @@ func (r *FirewallGroupReconciler) Reconcile(ctx context.Context, req ctrl.Reques
ipv6_done = true ipv6_done = true
} }
} }
if firewall_group.Name == ipv4_name+"-deleted" && len(ipv4) > 0 {
firewall_group.Name = ipv4_name
firewall_group.GroupMembers = ipv4
log.Info(fmt.Sprintf("Creating %s (from previously deleted)", ipv4_name))
_, err := r.UnifiClient.Client.UpdateFirewallGroup(context.Background(), r.UnifiClient.SiteID, &firewall_group)
if err != nil {
log.Error(err, "Could not update firewall group")
return ctrl.Result{}, err
}
ipv4_done = true
}
if firewall_group.Name == ipv6_name+"-deleted" && len(ipv6) > 0 {
firewall_group.Name = ipv6_name
firewall_group.GroupMembers = ipv6
log.Info(fmt.Sprintf("Creating %s (from previously deleted)", ipv6_name))
_, err := r.UnifiClient.Client.UpdateFirewallGroup(context.Background(), r.UnifiClient.SiteID, &firewall_group)
if err != nil {
log.Error(err, "Could not update firewall group")
return ctrl.Result{}, err
}
ipv6_done = true
}
} }
if len(ipv4) > 0 && !ipv4_done { if len(ipv4) > 0 && !ipv4_done {
log.Info(fmt.Sprintf("Creating %s", ipv4_name)) log.Info(fmt.Sprintf("Creating %s", ipv4_name))

View File

@@ -10,13 +10,19 @@ import (
"net/http" "net/http"
"net/http/cookiejar" "net/http/cookiejar"
"os" "os"
"strings"
"sync"
"github.com/vegardengen/go-unifi/unifi" "github.com/vegardengen/go-unifi/unifi"
) )
type UnifiClient struct { type UnifiClient struct {
Client *unifi.Client Client *unifi.Client
SiteID string SiteID string
mutex sync.Mutex
controller string
username string
password string
} }
func CreateUnifiClient() (*UnifiClient, error) { func CreateUnifiClient() (*UnifiClient, error) {
@@ -64,9 +70,57 @@ func CreateUnifiClient() (*UnifiClient, error) {
} }
unifiClient := &UnifiClient{ unifiClient := &UnifiClient{
Client: client, Client: client,
SiteID: siteID, SiteID: siteID,
controller: unifiURL,
username: username,
password: password,
} }
return unifiClient, nil return unifiClient, nil
} }
func (s *UnifiClient) WithSession(action func(c *unifi.Client) error) error {
s.mutex.Lock()
defer s.mutex.Unlock()
err := action(s.Client)
if err == nil {
return nil
}
if IsSessionExpired(err) {
if loginErr := s.Client.Login(context.Background(), s.username, s.password); loginErr != nil {
return fmt.Errorf("re-login to Unifi failed: %w", loginErr)
}
return action(s.Client)
}
return err
}
func (uClient *UnifiClient) Reauthenticate() error {
_, err := uClient.Client.ListSites(context.Background())
if err == nil {
return nil
}
if IsSessionExpired(err) {
if loginErr := uClient.Client.Login(context.Background(), uClient.username, uClient.password); loginErr != nil {
return fmt.Errorf("re-login to Unifi failed: %w", loginErr)
}
}
return nil
}
func IsSessionExpired(err error) bool {
if err == nil {
return false
}
msg := strings.ToLower(err.Error())
return strings.Contains(msg, "unauthorized") ||
strings.Contains(msg, "authentication") ||
strings.Contains(msg, "login required") ||
strings.Contains(msg, "token")
}