770af95afaed5327d975210a82ba89b24d96780d
[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 import socket
18 from time import time
19
20 import paramiko
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         logger.trace('Connect took {0} seconds'.format(time() - start))
67         logger.debug('New ssh: {0}'.format(client))
68         logger.debug('Connect peer: {0}'.
69                      format(client.get_transport().getpeername()))
70         logger.debug(client)
71
72         channel = client.get_transport().open_session()
73         channel.settimeout(time_out)
74         channel.set_combine_stderr(True)
75         channel.get_pty()
76         channel.invoke_subsystem("netconf")
77         logger.debug(channel)
78
79         self.client = client
80         self.channel = channel
81
82         # read OpenDaylight's hello message and capability list
83         self.get_response(
84             size=131072,
85             time_out=time_out,
86             err="Timeout on getting hello message."
87         )
88
89         self.channel.send(hello)
90         if not self.channel.active:
91             raise HoneycombError("Channel closed on capabilities exchange.")
92
93     def get_response(self, size=4096, time_out=10, err="Unspecified Error."):
94         """Iteratively read data from the receive buffer and catenate together
95         until message ends with the message delimiter, or
96         until timeout is reached.
97
98         :param size: Maximum number of bytes to read in one iteration.
99         :param time_out: Timeout value for getting the complete response.
100         :param err: Error message to provide when timeout is reached.
101         :type size:int
102         :type time_out:int
103         :type err:str
104         :returns: Content of response.
105         :rtype: str
106         :raises HoneycombError: If the read process times out.
107         """
108
109         reply = ''
110
111         try:
112             with timeout(time_out, exception=RuntimeError):
113                 while not reply.endswith(self.delimiter) or \
114                         self.channel.recv_ready():
115                     try:
116                         chunk = self.channel.recv(size)
117                         if not chunk:
118                             break
119                         reply += chunk
120                         if self.channel.exit_status_ready():
121                             logger.debug('Channel exit status ready.')
122                             break
123                     except socket.timeout:
124                         raise HoneycombError("Socket timeout.",
125                                              enable_logging=False)
126
127         except RuntimeError:
128             raise HoneycombError(err + " Content of buffer: {0}".format(reply),
129                                  enable_logging=False)
130
131         logger.trace(reply)
132         return reply.replace(self.delimiter, "")
133
134     def get_all_responses(self, size=4096, time_out=3):
135         """Read responses from the receive buffer and catenate together
136          until a read operation times out.
137
138         :param size: Maximum number of bytes to read in one iteration.
139         :param time_out: Timeout value for getting the complete response.
140         :type size:int
141         :type time_out:int
142         :returns: Content of response.
143         :rtype: str
144         """
145
146         response = ""
147         err = "Expected timeout occurred."
148
149         while True:
150             try:
151                 response += self.get_response(size, time_out, err)
152             except HoneycombError:
153                 break
154
155         return response
156
157     def send(self, message, **params):
158         """Sends provided message through the channel.
159
160         :param message: Message to be sent to Honeycomb.
161         :param params: Format the message string with these parameters.
162         :type message: str
163         :type params: dict
164         """
165
166         message = message.format(**params)
167
168         if not message.endswith(self.delimiter):
169             message += self.delimiter
170
171         logger.debug(message)
172
173         self.channel.send(message)

©2016 FD.io a Linux Foundation Collaborative Project. All Rights Reserved.
Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered trademark of Linus Torvalds.
Please see our privacy policy and terms of use.