The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7470

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Closes #7320

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
From 0367b3b51d80c63fd3d616c2c84025019238276c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@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 <stgra...@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
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to