Add client code from bcsaller
[osm/N2VC.git] / juju / client / connection.py
1 import asyncio
2 import json
3 import logging
4 import random
5 import ssl
6 import string
7 import websockets
8
9
10 log = logging.getLogger("websocket")
11
12 class Connection:
13 """
14 Usage:
15 client = await Connection.connect(info)
16 """
17 def __init__(self):
18 self.__requestId__ = 0
19 self.addr = None
20 self.ws = None
21
22 def _get_ssl(self, cert):
23 return ssl.create_default_context(
24 purpose=ssl.Purpose.CLIENT_AUTH, cadata=cert)
25
26 async def open(self, addr, cert=None):
27 kw = dict()
28 if cert:
29 kw['ssl'] = self._get_ssl(cert)
30 self.addr = addr
31 self.ws = await websockets.connect(addr, **kw)
32 return self
33
34 async def close(self):
35 await self.ws.close()
36
37 async def recv(self):
38 result = await self.ws.recv()
39 if result is not None:
40 result = json.loads(result)
41 return result
42
43 async def rpc(self, msg):
44 self.__requestID += 1
45 msg['RequestId'] = self.__requestID
46 if'Params' not in msg:
47 msg['Params'] = {}
48 if "Version" not in msg:
49 msg['Version'] = self.facades[msg['Type']]
50 outgoing = json.dumps(msg, indent=2)
51 await self.ws.send(outgoing)
52 result = await self.recv()
53 log.debug("send %s got %s", msg, result)
54 if result and 'Error' in result:
55 raise RuntimeError(result)
56 return result
57
58 @classmethod
59 async def connect(cls, info):
60 uuid = info.model_uuid
61 controller = info.controller
62 details = controller['details']
63 endpoint = "wss://{}/model/{}/api".format(
64 details['api-endpoints'][0],
65 entity.model_uuid)
66 client = cls()
67 await client.dial(endpoint, details['ca-cert'])
68 server_info = await client.login(info)
69 client.build_facades(server_info['facades'])
70 log.info("Driver connected to juju %s", endpoint)
71 return client
72
73 def build_facades(self, info):
74 self.facades.clear()
75 for facade in info:
76 self.facades[facade['Name']] = facade['Versions'][-1]
77
78 async def login(self, info):
79 account = info.account
80 result = await client.rpc({
81 "Type": "Admin",
82 "Request": "Login",
83 "Version": 3,
84 "Params": {
85 "auth-tag": "user-{}".format(account['user']),
86 "credentials": account['password'],
87 "Nonce": "".join(random.sample(string.printable, 12)),
88 }})
89 return result['Response']
90
91