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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """Implementation of keywords for managing Honeycomb notifications."""
19 from robot.api import logger
20 from interruptingcow import timeout
22 from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError
25 class Notifications(object):
26 """Implements keywords for managing Honeycomb notifications.
28 The keywords implemented in this class make it possible to:
29 - establish SSH session to Honeycomb host
30 - receive notifications from Honeycomb
31 - read received notifications
34 def __init__(self, hello, subscription):
36 :param hello: Hello message to be sent to Honeycomb.
37 :param subscription: rpc command to subscribe to Honeycomb notifications
40 :type subscription: str
42 Note: Passing the channel object as a robotframework argument closes
43 the channel. Class variables are used instead,
44 to persist the connection channel throughout the test case.
50 self.subscription = subscription
52 def create_session(self, node, time_out=10):
53 """Create an SSH session and connect to Honeycomb on the specified node.
55 :param node: Honeycomb node.
56 :param time_out: Timeout value for the connection in seconds.
62 client = paramiko.SSHClient()
63 client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
65 client.connect(node['host'],
66 username=node['honeycomb']['user'],
67 password=node['honeycomb']['passwd'],
69 port=node['honeycomb']['netconf_port'],
73 logger.trace('Connect took {0} seconds'.format(time() - start))
74 logger.debug('New ssh: {0}'.format(client))
75 logger.debug('Connect peer: {0}'.
76 format(client.get_transport().getpeername()))
79 channel = client.get_transport().open_session()
80 channel.settimeout(time_out)
82 channel.invoke_subsystem("netconf")
86 self.channel = channel
88 # read OpenDaylight's hello message and capability list
92 err="Timeout on getting hello message."
95 self.channel.send(self.hello)
96 if not self.channel.active:
97 raise HoneycombError("Channel closed on capabilities exchange.")
99 def _get_response(self, size=4096, time_out=10, err="Unspecified Error."):
100 """Iteratively read data from the receive buffer and catenate together
101 until message ends with the message delimiter, or
102 until timeout is reached.
104 :param size: Maximum number of bytes to read in one iteration.
105 :param time_out: Timeout value for getting the complete response.
106 :param err: Error message to provide when timeout is reached.
110 :return: Content of response.
112 :raises HoneycombError: If the read process times out.
118 with timeout(time_out, exception=RuntimeError):
119 while not reply.endswith(']]>]]>'):
120 if self.channel.recv_ready():
121 reply += self.channel.recv(size)
124 raise HoneycombError(err+" Content of buffer: {0}".format(reply))
129 def add_notification_listener(self, time_out=10):
130 """Open a new channel on the SSH session, connect to Netconf subsystem
131 and subscribe to receive Honeycomb notifications.
133 :param time_out: Timeout value for each read operation in seconds.
135 :raises HoneycombError: If subscription to notifications fails.
138 self.channel.send(self.subscription)
140 reply = self._get_response(
142 err="Timeout on notifications subscription."
145 if "<ok/>" not in reply:
146 raise HoneycombError("Notifications subscription failed with"
147 " message: {0}".format(reply))
149 logger.debug("Notifications subscription successful.")
151 def get_notification(self, time_out=10):
152 """Read and return the next notification message.
154 :param time_out: Timeout value for the read operation in seconds.
156 :return: Data received from buffer.
160 logger.debug("Getting notification.")
162 reply = self._get_response(
164 err="Timeout on getting notification."