CSIT-425: HC Test: NSH-SFC test suite
[csit.git] / resources / libraries / python / honeycomb / Netconf.py
1 # Copyright (c) 2016 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 from time import time
18
19 import paramiko
20 import socket
21 from robot.api import logger
22 from interruptingcow import timeout
23
24 from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError
25
26
27 class Netconf(object):
28     """Implements methods for creating and managing Netconf sessions."""
29
30     def __init__(self, delimiter=']]>]]>'):
31         """Initializer.
32
33         Note: Passing the channel object as a robotframework argument closes
34         the channel. Class variables are used instead,
35         to persist the connection channel throughout test cases.
36         """
37
38         self.client = None
39         self.channel = None
40         self.delimiter = delimiter
41
42     def create_session(self, node, hello, time_out=10):
43         """Create an SSH session, connect to Honeycomb on the specified node,
44         open a communication channel to the Netconf subsystem and exchange hello
45         messages.
46
47         :param node: Honeycomb node.
48         :param hello: Hello message and capability list to be sent to Honeycomb.
49         :param time_out: Timeout value for the connection in seconds.
50         :type node: dict
51         :type hello: str
52         :type time_out: int
53         """
54
55         start = time()
56         client = paramiko.SSHClient()
57         client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
58
59         client.connect(node['host'],
60                        username=node['honeycomb']['user'],
61                        password=node['honeycomb']['passwd'],
62                        pkey=None,
63                        port=node['honeycomb']['netconf_port'],
64                        timeout=time_out,
65                        )
66
67         logger.trace('Connect took {0} seconds'.format(time() - start))
68         logger.debug('New ssh: {0}'.format(client))
69         logger.debug('Connect peer: {0}'.
70                      format(client.get_transport().getpeername()))
71         logger.debug(client)
72
73         channel = client.get_transport().open_session()
74         channel.settimeout(time_out)
75         channel.set_combine_stderr(True)
76         channel.get_pty()
77         channel.invoke_subsystem("netconf")
78         logger.debug(channel)
79
80         self.client = client
81         self.channel = channel
82
83         # read OpenDaylight's hello message and capability list
84         self.get_response(
85             size=131072,
86             time_out=time_out,
87             err="Timeout on getting hello message."
88         )
89
90         self.channel.send(hello)
91         if not self.channel.active:
92             raise HoneycombError("Channel closed on capabilities exchange.")
93
94     def get_response(self, size=4096, time_out=10, err="Unspecified Error."):
95         """Iteratively read data from the receive buffer and catenate together
96         until message ends with the message delimiter, or
97         until timeout is reached.
98
99         :param size: Maximum number of bytes to read in one iteration.
100         :param time_out: Timeout value for getting the complete response.
101         :param err: Error message to provide when timeout is reached.
102         :type size:int
103         :type time_out:int
104         :type err:str
105         :return: Content of response.
106         :rtype: str
107         :raises HoneycombError: If the read process times out.
108         """
109
110         reply = ''
111
112         try:
113             with timeout(time_out, exception=RuntimeError):
114                 while not reply.endswith(self.delimiter) or \
115                         self.channel.recv_ready():
116                     try:
117                         chunk = self.channel.recv(size)
118                         if not chunk:
119                             break
120                         reply += chunk
121                         if self.channel.exit_status_ready():
122                             logger.debug('Channel exit status ready.')
123                             break
124                     except socket.timeout:
125                         raise HoneycombError("Socket timeout.",
126                                              enable_logging=False
127                                              )
128
129         except RuntimeError:
130             raise HoneycombError(err + " Content of buffer: {0}".format(reply),
131                                  enable_logging=False
132                                  )
133
134         logger.trace(reply)
135         return reply.replace(self.delimiter, "")
136
137     def get_all_responses(self, size=4096, time_out=3):
138         """Read responses from the receive buffer and catenate together
139          until a read operation times out.
140
141         :param size: Maximum number of bytes to read in one iteration.
142         :param time_out: Timeout value for getting the complete response.
143         :type size:int
144         :type time_out:int
145         :return: Content of response.
146         :rtype: str
147         """
148
149         response = ""
150         err = "Expected timeout occurred."
151
152         while True:
153             try:
154                 response += self.get_response(size, time_out, err)
155             except HoneycombError:
156                 break
157
158         return response
159
160     def send(self, message):
161         """Sends provided message through the channel.
162
163         :param message: Message to be sent to Honeycomb.
164         :type message: str
165         """
166
167         if not message.endswith(self.delimiter):
168             message += self.delimiter
169
170         self.channel.send(message)