|
|
@@ -16,12 +16,14 @@ import ( |
|
|
"strings"
|
|
|
"sync"
|
|
|
"sync/atomic"
|
|
|
+ "time"
|
|
|
|
|
|
"github.com/bmizerany/pat"
|
|
|
"github.com/gorilla/websocket"
|
|
|
"github.com/juju/errors"
|
|
|
"github.com/juju/loggo"
|
|
|
"github.com/juju/pubsub"
|
|
|
+ "github.com/juju/ratelimit"
|
|
|
"github.com/juju/utils"
|
|
|
"github.com/juju/utils/clock"
|
|
|
"golang.org/x/crypto/acme"
|
|
|
@@ -47,9 +49,19 @@ var logger = loggo.GetLogger("juju.apiserver") |
|
|
|
|
|
var defaultHTTPMethods = []string{"GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS"}
|
|
|
|
|
|
-// loginRateLimit defines how many concurrent Login requests we will
|
|
|
-// accept
|
|
|
-const loginRateLimit = 10
|
|
|
+const (
|
|
|
+ // loginRateLimit defines how many concurrent Login requests we will
|
|
|
+ // accept.
|
|
|
+ loginRateLimit = 10
|
|
|
+
|
|
|
+ // logSinkBurst defines the number of log messages that will be
|
|
|
+ // let through before we start rate limiting.
|
|
|
+ logSinkBurst = 1000
|
|
|
+
|
|
|
+ // logSinkRefillRate defines the rate at which log messages will be
|
|
|
+ // let through once the initial burst amount has been depleted.
|
|
|
+ logSinkRefillRate = time.Millisecond
|
|
|
+)
|
|
|
|
|
|
// Server holds the server side of the API.
|
|
|
type Server struct {
|
|
|
@@ -432,11 +444,25 @@ func (srv *Server) endpoints() []apihttp.Endpoint { |
|
|
add("/model/:modeluuid/logstream", logStreamHandler)
|
|
|
add("/model/:modeluuid/log", debugLogHandler)
|
|
|
|
|
|
- logSinkHandler := newLogSinkHandler(httpCtxt, srv.logSinkWriter, newAgentLoggingStrategy)
|
|
|
+ logSinkHandler := newLogSinkHandler(
|
|
|
+ httpCtxt,
|
|
|
+ srv.logSinkWriter,
|
|
|
+ newAgentLoggingStrategy,
|
|
|
+ srv.clock,
|
|
|
+ ratelimit.NewBucketWithClock(
|
|
|
+ logSinkRefillRate, logSinkBurst, ratelimitClock{srv.clock},
|
|
|
+ ),
|
|
|
+ )
|
|
|
add("/model/:modeluuid/logsink", srv.trackRequests(logSinkHandler))
|
|
|
|
|
|
// We don't need to save the migrated logs to a logfile as well as to the DB.
|
|
|
- logTransferHandler := newLogSinkHandler(httpCtxt, ioutil.Discard, newMigrationLoggingStrategy)
|
|
|
+ logTransferHandler := newLogSinkHandler(
|
|
|
+ httpCtxt,
|
|
|
+ ioutil.Discard,
|
|
|
+ newMigrationLoggingStrategy,
|
|
|
+ srv.clock,
|
|
|
+ nil, // do not rate-limit log migration
|
|
|
+ )
|
|
|
add("/migrate/logtransfer", srv.trackRequests(logTransferHandler))
|
|
|
|
|
|
modelRestHandler := &modelRestHandler{
|
|
|
@@ -855,3 +881,13 @@ func (srv *Server) processModelRemovals() error { |
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// ratelimitClock adapts clock.Clock to ratelimit.Clock.
|
|
|
+type ratelimitClock struct {
|
|
|
+ clock.Clock
|
|
|
+}
|
|
|
+
|
|
|
+// Sleep is defined by the ratelimit.Clock interface.
|
|
|
+func (c ratelimitClock) Sleep(d time.Duration) {
|
|
|
+ <-c.Clock.After(d)
|
|
|
+}
|
0 comments on commit
e77cbf1