-import asyncio
import io
import json
import logging
import os
import random
+import shlex
import ssl
import string
+import subprocess
import websockets
import yaml
+from juju.errors import JujuAPIError
+
log = logging.getLogger("websocket")
self.ws = None
self.facades = {}
+ @property
+ def is_open(self):
+ if self.ws:
+ return self.ws.open
+ return False
+
def _get_ssl(self, cert):
return ssl.create_default_context(
purpose=ssl.Purpose.CLIENT_AUTH, cadata=cert)
async def rpc(self, msg, encoder=None):
self.__request_id__ += 1
- msg['RequestId'] = self.__request_id__
- if'Params' not in msg:
- msg['Params'] = {}
- if "Version" not in msg:
- msg['Version'] = self.facades[msg['Type']]
+ msg['request-id'] = self.__request_id__
+ if'params' not in msg:
+ msg['params'] = {}
+ if "version" not in msg:
+ msg['version'] = self.facades[msg['type']]
outgoing = json.dumps(msg, indent=2, cls=encoder)
await self.ws.send(outgoing)
result = await self.recv()
- log.debug("send %s got %s", msg, result)
- if result and 'Error' in result:
- raise RuntimeError(result)
+ #log.debug("Send: %s", outgoing)
+ #log.debug("Recv: %s", result)
+ if result and 'error' in result:
+ raise JujuAPIError(result)
return result
async def clone(self):
self.cacert,
)
+ async def controller(self):
+ """Return a Connection to the controller at self.endpoint
+
+ """
+ return await Connection.connect(
+ self.endpoint,
+ None,
+ self.username,
+ self.password,
+ self.cacert,
+ )
+
@classmethod
async def connect(cls, endpoint, uuid, username, password, cacert=None):
- url = "wss://{}/model/{}/api".format(endpoint, uuid)
+ """Connect to the websocket.
+
+ If uuid is None, the connection will be to the controller. Otherwise it
+ will be to the model.
+
+ """
+ if uuid:
+ url = "wss://{}/model/{}/api".format(endpoint, uuid)
+ else:
+ url = "wss://{}/api".format(endpoint)
client = cls(endpoint, uuid, username, password, cacert)
await client.open(url, cacert)
server_info = await client.login(username, password)
client.build_facades(server_info['facades'])
- log.info("Driver connected to juju %s", endpoint)
+ log.info("Driver connected to juju %s", url)
return client
endpoint = controller['api-endpoints'][0]
cacert = controller.get('ca-cert')
accounts = jujudata.accounts()[controller_name]
- username = accounts['current-account']
- password = accounts['accounts'][username]['password']
- models = jujudata.models()[controller_name]['accounts'][username]
+ username = accounts['user']
+ password = accounts['password']
+ models = jujudata.models()[controller_name]
model_name = models['current-model']
model_uuid = models['models'][model_name]['uuid']
endpoint = controller['api-endpoints'][0]
cacert = controller.get('ca-cert')
accounts = jujudata.accounts()[controller_name]
- username = accounts['current-account']
- password = accounts['accounts'][username]['password']
- models = jujudata.models()[controller_name]['accounts'][username]
+ username = accounts['user']
+ password = accounts['password']
+ models = jujudata.models()[controller_name]
model_uuid = models['models'][model_name]['uuid']
return await cls.connect(
def build_facades(self, info):
self.facades.clear()
for facade in info:
- self.facades[facade['Name']] = facade['Versions'][-1]
+ self.facades[facade['name']] = facade['versions'][-1]
async def login(self, username, password):
if not username.startswith('user-'):
username = 'user-{}'.format(username)
result = await self.rpc({
- "Type": "Admin",
- "Request": "Login",
- "Version": 3,
- "Params": {
+ "type": "Admin",
+ "request": "Login",
+ "version": 3,
+ "params": {
"auth-tag": username,
"credentials": password,
- "Nonce": "".join(random.sample(string.printable, 12)),
+ "nonce": "".join(random.sample(string.printable, 12)),
}})
- return result['Response']
+ return result['response']
class JujuData:
self.path = os.path.abspath(os.path.expanduser(self.path))
def current_controller(self):
- try:
- filepath = os.path.join(self.path, 'current-controller')
- with io.open(filepath, 'rt') as f:
- return f.read().strip()
- except OSError as e:
- log.exception(e)
- return None
+ cmd = shlex.split('juju show-controller --format yaml')
+ output = subprocess.check_output(cmd)
+ output = yaml.safe_load(output)
+ return list(output.keys())[0]
def controllers(self):
return self._load_yaml('controllers.yaml', 'controllers')