[lxc-devel] [lxd/master] lxd/rbac: New notification API
stgraber on Github
lxc-bot at linuxcontainers.org
Fri May 29 13:05:21 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 370 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200529/fe8268b9/attachment.bin>
-------------- next part --------------
From 0367b3b51d80c63fd3d616c2c84025019238276c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 21 May 2020 14:28:28 -0400
Subject: [PATCH] lxd/rbac: New notification API
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes #7320
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/rbac/server.go | 97 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 85 insertions(+), 12 deletions(-)
diff --git a/lxd/rbac/server.go b/lxd/rbac/server.go
index 392e9c5b50..e86fad373b 100644
--- a/lxd/rbac/server.go
+++ b/lxd/rbac/server.go
@@ -2,6 +2,7 @@ package rbac
import (
"bytes"
+ "context"
"encoding/json"
"errors"
"fmt"
@@ -37,7 +38,7 @@ type rbacResourcePostResponse struct {
}
type rbacStatus struct {
- LastChange time.Time `json:"last-change"`
+ LastChange string `json:"last-change"`
}
// Server represents an RBAC server.
@@ -47,8 +48,10 @@ type Server struct {
lastSyncID string
client *httpbakery.Client
- lastChange time.Time
- statusDone chan int
+ lastChange string
+
+ ctx context.Context
+ ctxCancel context.CancelFunc
resources map[string]string // Maps name to identifier
resourcesLock sync.Mutex
@@ -66,13 +69,15 @@ func NewServer(apiURL string, apiKey string, agentAuthURL string, agentUsername
apiURL: apiURL,
apiKey: apiKey,
lastSyncID: "",
- lastChange: time.Time{},
+ lastChange: "",
resources: make(map[string]string),
permissions: make(map[string]map[string][]string),
permissionsLock: &sync.Mutex{},
}
- //
+ // Setup context
+ r.ctx, r.ctxCancel = context.WithCancel(context.Background())
+
var keyPair bakery.KeyPair
keyPair.Private.UnmarshalText([]byte(agentPrivateKey))
keyPair.Public.UnmarshalText([]byte(agentPublicKey))
@@ -101,19 +106,87 @@ func NewServer(apiURL string, apiKey string, agentAuthURL string, agentUsername
return &r, nil
}
-// StartStatusCheck starts a periodic status checker.
+// StartStatusCheck runs a status checking loop.
func (r *Server) StartStatusCheck() {
- // Initialize the last changed timestamp
+ var status rbacStatus
+
+ // Figure out the new URL.
+ u, err := url.Parse(r.apiURL)
+ if err != nil {
+ logger.Errorf("Failed to parse RBAC url: %v", err)
+ return
+ }
+ u.Path = path.Join(u.Path, "/api/service/v1/changes")
+
+ go func() {
+ for {
+ if status.LastChange != "" {
+ values := url.Values{}
+ values.Set("last-change", status.LastChange)
+ u.RawQuery = values.Encode()
+ }
+
+ req, err := http.NewRequestWithContext(r.ctx, "GET", u.String(), nil)
+ if err != nil {
+ if err == context.Canceled {
+ return
+ }
+
+ logger.Errorf("Failed to prepare RBAC query: %v", err)
+ return
+ }
+
+ resp, err := r.client.Do(req)
+ if err != nil {
+ resp.Body.Close()
+ if err == context.Canceled {
+ return
+ }
+
+ logger.Errorf("Failed to hit new RBAC URL, falling back: %v", err)
+ r.oldStatusCheck()
+ return
+ }
+
+ if resp.StatusCode == 404 {
+ resp.Body.Close()
+ logger.Debugf("RBAC server doesn't support new monitoring API, falling back.")
+ r.oldStatusCheck()
+ return
+ }
+
+ if resp.StatusCode != 200 {
+ resp.Body.Close()
+ logger.Debugf("RBAC server disconnected, re-connecting. (code=%v)", resp.StatusCode)
+ continue
+ }
+
+ err = json.NewDecoder(resp.Body).Decode(&status)
+ resp.Body.Close()
+ if err != nil {
+ logger.Errorf("Failed to parse RBAC response, re-trying: %v", err)
+ continue
+ }
+
+ r.lastChange = status.LastChange
+ logger.Debugf("RBAC change detected, flushing cache")
+ r.flushCache()
+ }
+ }()
+}
+
+func (r *Server) oldStatusCheck() {
+ // NOTE: Can be dropped once new RBAC hits stable.
r.hasStatusChanged()
- r.statusDone = make(chan int)
go func() {
for {
select {
- case <-r.statusDone:
+ case <-r.ctx.Done():
return
case <-time.After(time.Minute):
if r.hasStatusChanged() {
+ logger.Debugf("RBAC change detected, flushing cache")
r.flushCache()
}
}
@@ -123,7 +196,7 @@ func (r *Server) StartStatusCheck() {
// StopStatusCheck stops the periodic status checker.
func (r *Server) StopStatusCheck() {
- close(r.statusDone)
+ r.ctxCancel()
}
// SyncProjects updates the list of projects in RBAC
@@ -272,12 +345,12 @@ func (r *Server) hasStatusChanged() bool {
return true
}
- if r.lastChange.IsZero() {
+ if r.lastChange == "" {
r.lastChange = status.LastChange
return true
}
- hasChanged := !r.lastChange.Equal(status.LastChange)
+ hasChanged := r.lastChange != status.LastChange
r.lastChange = status.LastChange
return hasChanged
More information about the lxc-devel
mailing list