summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
13d73a3)
The default max message / frame size for the websocket library is 1MB.
However, the initial AllWatcher response for large models can exceed
that. Increased the default to 4MB and made it configurable.
Fixes #136
Note: Any connection method or constructor can accept an optional `loop`
argument to override the default event loop from `asyncio.get_event_loop`.
"""
Note: Any connection method or constructor can accept an optional `loop`
argument to override the default event loop from `asyncio.get_event_loop`.
"""
+
+ DEFAULT_FRAME_SIZE = 'default_frame_size'
+ MAX_FRAME_SIZE = 2**22
+ "Maximum size for a single frame. Defaults to 4MB."
+
def __init__(
self, endpoint, uuid, username, password, cacert=None,
def __init__(
self, endpoint, uuid, username, password, cacert=None,
- macaroons=None, loop=None):
+ macaroons=None, loop=None, max_frame_size=DEFAULT_FRAME_SIZE):
self.endpoint = endpoint
self.uuid = uuid
if macaroons:
self.endpoint = endpoint
self.uuid = uuid
if macaroons:
self.facades = {}
self.messages = IdQueue(loop=self.loop)
self.monitor = Monitor(connection=self)
self.facades = {}
self.messages = IdQueue(loop=self.loop)
self.monitor = Monitor(connection=self)
+ if max_frame_size is self.DEFAULT_FRAME_SIZE:
+ max_frame_size = self.MAX_FRAME_SIZE
+ self.max_frame_size = max_frame_size
@property
def is_open(self):
@property
def is_open(self):
kw = dict()
kw['ssl'] = self._get_ssl(self.cacert)
kw['loop'] = self.loop
kw = dict()
kw['ssl'] = self._get_ssl(self.cacert)
kw['loop'] = self.loop
+ kw['max_size'] = self.max_frame_size
self.addr = url
self.ws = await websockets.connect(url, **kw)
self.loop.create_task(self.receiver())
self.addr = url
self.ws = await websockets.connect(url, **kw)
self.loop.create_task(self.receiver())
self.cacert,
self.macaroons,
self.loop,
self.cacert,
self.macaroons,
self.loop,
)
async def controller(self):
)
async def controller(self):
@classmethod
async def connect(
cls, endpoint, uuid, username, password, cacert=None,
@classmethod
async def connect(
cls, endpoint, uuid, username, password, cacert=None,
- macaroons=None, loop=None):
+ macaroons=None, loop=None, max_frame_size=None):
"""Connect to the websocket.
If uuid is None, the connection will be to the controller. Otherwise it
"""Connect to the websocket.
If uuid is None, the connection will be to the controller. Otherwise it
"""
client = cls(endpoint, uuid, username, password, cacert, macaroons,
"""
client = cls(endpoint, uuid, username, password, cacert, macaroons,
endpoints = [(endpoint, cacert)]
while endpoints:
_endpoint, _cacert = endpoints.pop(0)
endpoints = [(endpoint, cacert)]
while endpoints:
_endpoint, _cacert = endpoints.pop(0)
return client
@classmethod
return client
@classmethod
- async def connect_current(cls, loop=None):
+ async def connect_current(cls, loop=None, max_frame_size=None):
"""Connect to the currently active model.
"""
"""Connect to the currently active model.
"""
model_name = jujudata.current_model()
return await cls.connect_model(
model_name = jujudata.current_model()
return await cls.connect_model(
- '{}:{}'.format(controller_name, model_name), loop)
+ '{}:{}'.format(controller_name, model_name), loop, max_frame_size)
- async def connect_current_controller(cls, loop=None):
+ async def connect_current_controller(cls, loop=None, max_frame_size=None):
"""Connect to the currently active controller.
"""
"""Connect to the currently active controller.
"""
if not controller_name:
raise JujuConnectionError('No current controller')
if not controller_name:
raise JujuConnectionError('No current controller')
- return await cls.connect_controller(controller_name, loop)
+ return await cls.connect_controller(controller_name, loop,
+ max_frame_size)
- async def connect_controller(cls, controller_name, loop=None):
+ async def connect_controller(cls, controller_name, loop=None,
+ max_frame_size=None):
"""Connect to a controller by name.
"""
"""Connect to a controller by name.
"""
macaroons = get_macaroons(controller_name) if not password else None
return await cls.connect(
macaroons = get_macaroons(controller_name) if not password else None
return await cls.connect(
- endpoint, None, username, password, cacert, macaroons, loop)
+ endpoint, None, username, password, cacert, macaroons, loop,
+ max_frame_size)
- async def connect_model(cls, model, loop=None):
+ async def connect_model(cls, model, loop=None, max_frame_size=None):
"""Connect to a model by name.
:param str model: [<controller>:]<model>
"""Connect to a model by name.
:param str model: [<controller>:]<model>
macaroons = get_macaroons(controller_name) if not password else None
return await cls.connect(
macaroons = get_macaroons(controller_name) if not password else None
return await cls.connect(
- endpoint, model_uuid, username, password, cacert, macaroons, loop)
+ endpoint, model_uuid, username, password, cacert, macaroons, loop,
+ max_frame_size)
def build_facades(self, facades):
self.facades.clear()
def build_facades(self, facades):
self.facades.clear()
class Controller(object):
class Controller(object):
- def __init__(self, loop=None):
+ def __init__(self, loop=None,
+ max_frame_size=connection.Connection.DEFAULT_FRAME_SIZE):
"""Instantiate a new Controller.
One of the connect_* methods will need to be called before this
"""Instantiate a new Controller.
One of the connect_* methods will need to be called before this
"""
self.loop = loop or asyncio.get_event_loop()
"""
self.loop = loop or asyncio.get_event_loop()
+ self.max_frame_size = None
self.connection = None
self.controller_name = None
self.connection = None
self.controller_name = None
"""
self.connection = await connection.Connection.connect(
"""
self.connection = await connection.Connection.connect(
- endpoint, None, username, password, cacert, macaroons)
+ endpoint, None, username, password, cacert, macaroons,
+ max_frame_size=self.max_frame_size)
async def connect_current(self):
"""Connect to the current Juju controller.
"""
self.connection = (
async def connect_current(self):
"""Connect to the current Juju controller.
"""
self.connection = (
- await connection.Connection.connect_current_controller())
+ await connection.Connection.connect_current_controller(
+ max_frame_size=self.max_frame_size))
async def connect_controller(self, controller_name):
"""Connect to a Juju controller by name.
"""
self.connection = (
async def connect_controller(self, controller_name):
"""Connect to a Juju controller by name.
"""
self.connection = (
- await connection.Connection.connect_controller(controller_name))
+ await connection.Connection.connect_controller(
+ controller_name, max_frame_size=self.max_frame_size))
self.controller_name = controller_name
async def disconnect(self):
self.controller_name = controller_name
async def disconnect(self):
self.connection)
return await controller_facade.AllModels()
self.connection)
return await controller_facade.AllModels()
def get_payloads(self, *patterns):
"""Return list of known payloads.
def get_payloads(self, *patterns):
"""Return list of known payloads.
client_facade = client.UserManagerFacade.from_connection(
self.connection)
user = tag.user(username)
client_facade = client.UserManagerFacade.from_connection(
self.connection)
user = tag.user(username)
- return await client_facade.UserInfo([client.Entity(user)], include_disabled)
+ return await client_facade.UserInfo([client.Entity(user)],
+ include_disabled)
async def grant(self, username, acl='login'):
"""Set access level of the given user on the controller
async def grant(self, username, acl='login'):
"""Set access level of the given user on the controller
"""
The main API for interacting with a Juju model.
"""
"""
The main API for interacting with a Juju model.
"""
- def __init__(self, loop=None):
+ def __init__(self, loop=None,
+ max_frame_size=connection.Connection.DEFAULT_FRAME_SIZE):
"""Instantiate a new connected Model.
:param loop: an asyncio event loop
"""Instantiate a new connected Model.
:param loop: an asyncio event loop
+ :param max_frame_size: See
+ `juju.client.connection.Connection.MAX_FRAME_SIZE`
"""
self.loop = loop or asyncio.get_event_loop()
"""
self.loop = loop or asyncio.get_event_loop()
+ self.max_frame_size = max_frame_size
self.connection = None
self.observers = weakref.WeakValueDictionary()
self.state = ModelState(self)
self.connection = None
self.observers = weakref.WeakValueDictionary()
self.state = ModelState(self)
"""
if 'loop' not in kw:
kw['loop'] = self.loop
"""
if 'loop' not in kw:
kw['loop'] = self.loop
+ if 'max_frame_size' not in kw:
+ kw['max_frame_size'] = self.max_frame_size
self.connection = await connection.Connection.connect(*args, **kw)
await self._after_connect()
self.connection = await connection.Connection.connect(*args, **kw)
await self._after_connect()
"""
self.connection = await connection.Connection.connect_current(
"""
self.connection = await connection.Connection.connect_current(
+ self.loop, max_frame_size=self.max_frame_size)
await self._after_connect()
async def connect_model(self, model_name):
await self._after_connect()
async def connect_model(self, model_name):
:param model_name: Format [controller:][user/]model
"""
:param model_name: Format [controller:][user/]model
"""
- self.connection = await connection.Connection.connect_model(model_name,
- self.loop)
+ self.connection = await connection.Connection.connect_model(
+ model_name, self.loop, self.max_frame_size)
await self._after_connect()
async def _after_connect(self):
await self._after_connect()
async def _after_connect(self):
pytest-xdist
mock
asynctest
pytest-xdist
mock
asynctest
[testenv:py35]
# default tox env excludes integration tests
[testenv:py35]
# default tox env excludes integration tests