fix failing tests after namespace updates in HC
[csit.git] / resources / libraries / python / honeycomb / Netconf.py
1 # Copyright (c) 2018 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Keywords used to connect to Honeycomb through Netconf, send messages
15  and receive replies."""
16
17 import socket
18 from time import time
19
20 import paramiko
21 from robot.api import logger
22
23 from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError
24
25
26 class Netconf(object):
27     """Implements methods for creating and managing Netconf sessions."""
28
29     def __init__(self, delimiter=']]>]]>'):
30         """Initializer.
31
32         Note: Passing the channel object as a robotframework argument closes
33         the channel. Class variables are used instead,
34         to persist the connection channel throughout test cases.
35         """
36
37         self.client = None
38         self.channel = None
39         self.delimiter = delimiter
40
41     def create_session(self, node, hello, time_out=10):
42         """Create an SSH session, connect to Honeycomb on the specified node,
43         open a communication channel to the Netconf subsystem and exchange hello
44         messages.
45
46         :param node: Honeycomb node.
47         :param hello: Hello message and capability list to be sent to Honeycomb.
48         :param time_out: Timeout value for the connection in seconds.
49         :type node: dict
50         :type hello: str
51         :type time_out: int
52         """
53
54         start = time()
55         client = paramiko.SSHClient()
56         client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
57
58         client.connect(node['host'],
59                        username=node['honeycomb']['user'],
60                        password=node['honeycomb']['passwd'],
61                        pkey=None,
62                        port=node['honeycomb']['netconf_port'],
63                        timeout=time_out)
64
65         logger.trace('Connect took {0} seconds'.format(time() - start))
66         logger.debug('New ssh: {0}'.format(client))
67         logger.debug('Connect peer: {0}'.
68                      format(client.get_transport().getpeername()))
69         logger.debug(client)
70
71         channel = client.get_transport().open_session()
72         channel.settimeout(time_out)
73         channel.set_combine_stderr(True)
74         channel.get_pty()
75         channel.invoke_subsystem("netconf")
76         logger.debug(channel)
77
78         self.client = client
79         self.channel = channel
80
81         # read OpenDaylight's hello message and capability list
82         self.get_response(
83             size=131072,
84             err="Timeout on getting hello message."
85         )
86
87         self.channel.send(hello)
88         if not self.channel.active:
89             raise HoneycombError("Channel closed on capabilities exchange.")
90
91     def get_response(self, size=4096, err="Unspecified Error."):
92         """Iteratively read data from the receive buffer and catenate together
93         until message ends with the message delimiter, or
94         until timeout is reached.
95
96         :param size: Maximum number of bytes to read in one iteration.
97         :param err: Error message to provide when timeout is reached.
98         :type size: int
99         :type err: str
100         :returns: Content of response.
101         :rtype: str
102         :raises HoneycombError: If the read process times out.
103         """
104
105         reply = ''
106
107         try:
108             while not reply.endswith(self.delimiter) or \
109                     self.channel.recv_ready():
110                 try:
111                     chunk = self.channel.recv(size)
112                     if not chunk:
113                         break
114                     reply += chunk
115                     if self.channel.exit_status_ready():
116                         logger.debug('Channel exit status ready.')
117                         break
118                 except socket.timeout:
119                     raise HoneycombError("Socket timeout.",
120                                          enable_logging=False)
121
122         except RuntimeError:
123             raise HoneycombError(err + " Content of buffer: {0}".format(reply),
124                                  enable_logging=False)
125
126         logger.trace(reply)
127         return reply.replace(self.delimiter, "")
128
129     def get_all_responses(self, size=4096, time_out=3):
130         """Read responses from the receive buffer and catenate together
131         until a read operation times out.
132
133         :param size: Maximum number of bytes to read in one iteration.
134         :param time_out: Timeout value for getting the complete response.
135         :type size: int
136         :type time_out: int
137         :returns: Content of response.
138         :rtype: str
139         """
140
141         response = ""
142         err = "Expected timeout occurred."
143
144         while True:
145             try:
146                 response += self.get_response(size, err)
147             except HoneycombError:
148                 break
149
150         return response
151
152     def send(self, message, **params):
153         """Sends provided message through the channel.
154
155         :param message: Message to be sent to Honeycomb.
156         :param params: Format the message string with these parameters.
157         :type message: str
158         :type params: dict
159         """
160
161         message = message.format(**params)
162
163         if not message.endswith(self.delimiter):
164             message += self.delimiter
165
166         logger.debug(message)
167
168         self.channel.send(message)