X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=juju%2Fclient%2Fconnection.py;h=aea1a1c78d9c6a1ef0638b9fb1867820096f5065;hb=1bd3bd858aaf21ecccc64134c536d105c10b0d7e;hp=1a9e8e9df9ff939b6b9a84b4d1a9282c46c160b4;hpb=40e869ca5f14b824c6ae4a7e2d23d940af25a492;p=osm%2FN2VC.git diff --git a/juju/client/connection.py b/juju/client/connection.py index 1a9e8e9..aea1a1c 100644 --- a/juju/client/connection.py +++ b/juju/client/connection.py @@ -4,8 +4,10 @@ import json import logging import os import random +import shlex import ssl import string +import subprocess import websockets import yaml @@ -28,7 +30,13 @@ class Connection: client = await Connection.connect_current() """ - def __init__(self): + def __init__(self, endpoint, uuid, username, password, cacert=None): + self.endpoint = endpoint + self.uuid = uuid + self.username = username + self.password = password + self.cacert = cacert + self.__request_id__ = 0 self.addr = None self.ws = None @@ -57,27 +65,62 @@ class Connection: 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: + if result and 'error' in result: raise RuntimeError(result) return result + async def clone(self): + """Return a new Connection, connected to the same websocket endpoint + as this one. + + """ + return await Connection.connect( + self.endpoint, + self.uuid, + self.username, + self.password, + 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) - client = cls() + """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 @classmethod @@ -91,9 +134,9 @@ class Connection: 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'] @@ -114,9 +157,9 @@ class Connection: 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( @@ -125,22 +168,22 @@ class Connection: 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: @@ -149,13 +192,10 @@ 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')