blob: 6d530f66a712ec68ca0515cf3aad8a49b44a3499 [file] [log] [blame]
Zack Williams41513bf2018-07-07 20:08:35 -07001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
Stephane Barbarie52198b92017-03-02 13:44:46 -050014from unittest import main
15from common.utils.consulhelpers import get_endpoint_from_consul
Richard Jankowski87289342018-04-19 13:59:10 -040016from tests.itests.test_utils import get_pod_ip, \
Stephane Barbariecc6b2e62017-03-02 14:35:55 -050017 run_long_running_command_with_timeout
Stephane Barbarie52198b92017-03-02 13:44:46 -050018from tests.itests.voltha.rest_base import RestBase
19from google.protobuf.json_format import MessageToDict
20from voltha.protos.device_pb2 import Device
21import simplejson, jsonschema
22import re
Richard Jankowski87289342018-04-19 13:59:10 -040023from tests.itests.orch_environment import get_orch_environment
24from testconfig import config
Stephane Barbarie52198b92017-03-02 13:44:46 -050025
26# ~~~~~~~ Common variables ~~~~~~~
27
28LOCAL_CONSUL = "localhost:8500"
Richard Jankowski87289342018-04-19 13:59:10 -040029ENV_DOCKER_COMPOSE = 'docker-compose'
30ENV_K8S_SINGLE_NODE = 'k8s-single-node'
31
32orch_env = ENV_DOCKER_COMPOSE
33if 'test_parameters' in config and 'orch_env' in config['test_parameters']:
34 orch_env = config['test_parameters']['orch_env']
35print 'orchestration-environment: %s' % orch_env
Stephane Barbarie52198b92017-03-02 13:44:46 -050036
37COMMANDS = dict(
38 kafka_client_run="kafkacat -b {} -L",
Stephane Barbariee37300e2017-06-08 11:22:16 -040039 kafka_client_send_msg='echo hello | kafkacat -b {} -P -t voltha.alarms -c 1',
40 kafka_client_alarm_check="kafkacat -o end -b {} -C -t voltha.alarms -c 2",
Stephane Barbarie52198b92017-03-02 13:44:46 -050041)
42
43ALARM_SCHEMA = {
44 "type": "object",
45 "properties": {
46 "id": {"type": "string"},
47 "type": {"type": "string"},
48 "category": {"type": "string"},
49 "state": {"type": "string"},
50 "severity": {"type": "string"},
51 "resource_id": {"type": "string"},
52 "raised_ts": {"type": "number"},
53 "reported_ts": {"type": "number"},
54 "changed_ts": {"type": "number"},
55 "description": {"type": "string"},
56 "context": {
57 "type": "object",
58 "additionalProperties": {"type": "string"}
59 }
60 }
61}
62
63
Stephane Barbariecc6b2e62017-03-02 14:35:55 -050064# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarie52198b92017-03-02 13:44:46 -050065
66
67class VolthaAlarmEventTests(RestBase):
Richard Jankowski87289342018-04-19 13:59:10 -040068 # Get endpoint info
69 if orch_env == ENV_K8S_SINGLE_NODE:
70 rest_endpoint = get_pod_ip('voltha') + ':8443'
71 kafka_endpoint = get_pod_ip('kafka')
72 else:
73 rest_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'voltha-envoy-8443')
74 kafka_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'kafka')
Stephane Barbarie52198b92017-03-02 13:44:46 -050075
76 # Construct the base_url
ubuntuc5c83d72017-07-01 17:57:19 -070077 base_url = 'https://' + rest_endpoint
Stephane Barbarie52198b92017-03-02 13:44:46 -050078
Stephane Barbarie52198b92017-03-02 13:44:46 -050079 # ~~~~~~~~~~~~ Tests ~~~~~~~~~~~~
80
Stephane Barbariee37300e2017-06-08 11:22:16 -040081 def test_1_alarm_topic_exists(self):
82 # Produce a message to ensure that the topic exists
83 cmd = COMMANDS['kafka_client_send_msg'].format(self.kafka_endpoint)
84 run_long_running_command_with_timeout(cmd, 5)
85
Stephane Barbarie52198b92017-03-02 13:44:46 -050086 # We want to make sure that the topic is available on the system
87 expected_pattern = ['voltha.alarms']
88
89 # Start the kafka client to retrieve details on topics
90 cmd = COMMANDS['kafka_client_run'].format(self.kafka_endpoint)
91 kafka_client_output = run_long_running_command_with_timeout(cmd, 20)
92
93 # Loop through the kafka client output to find the topic
94 found = False
95 for out in kafka_client_output:
96 if all(ep in out for ep in expected_pattern):
97 found = True
98 break
99
Stephane Barbariecc6b2e62017-03-02 14:35:55 -0500100 self.assertTrue(found,
101 'Failed to find topic {}'.format(expected_pattern))
Stephane Barbarie52198b92017-03-02 13:44:46 -0500102
Stephane Barbariee37300e2017-06-08 11:22:16 -0400103 def test_2_alarm_generated_by_adapter(self):
Stephane Barbarie52198b92017-03-02 13:44:46 -0500104 # Verify that REST calls can be made
105 self.verify_rest()
106
107 # Create a new device
108 device = self.add_device()
109
110 # Activate the new device
111 self.activate_device(device['id'])
112
113 # The simulated olt device should start generating alarms periodically
114 alarm = self.get_alarm_event(device['id'])
115
116 # Make sure that the schema is valid
117 self.validate_alarm_event_schema(alarm)
118
119 # Validate the constructed alarm id
120 self.verify_alarm_event_id(device['id'], alarm['id'])
121
122 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123
124 # Make sure the Voltha REST interface is available
125 def verify_rest(self):
126 self.get('/api/v1')
127
128 # Create a new simulated device
129 def add_device(self):
130 device = Device(
131 type='simulated_olt',
Richard Jankowski87289342018-04-19 13:59:10 -0400132 mac_address='00:00:00:00:00:01'
Stephane Barbarie52198b92017-03-02 13:44:46 -0500133 )
Stephane Barbariecd51f992017-09-07 16:37:02 -0400134 device = self.post('/api/v1/devices', MessageToDict(device),
135 expected_http_code=200)
Stephane Barbarie52198b92017-03-02 13:44:46 -0500136 return device
137
Stephane Barbariecc6b2e62017-03-02 14:35:55 -0500138 # Active the simulated device.
139 # This will trigger the simulation of random alarms
Stephane Barbarie52198b92017-03-02 13:44:46 -0500140 def activate_device(self, device_id):
Stephane Barbariecd51f992017-09-07 16:37:02 -0400141 path = '/api/v1/devices/{}'.format(device_id)
142 self.post(path + '/enable', expected_http_code=200)
Stephane Barbarie52198b92017-03-02 13:44:46 -0500143 device = self.get(path)
144 self.assertEqual(device['admin_state'], 'ENABLED')
145
146 # Retrieve a sample alarm for a specific device
147 def get_alarm_event(self, device_id):
148 cmd = COMMANDS['kafka_client_alarm_check'].format(self.kafka_endpoint)
Stephane Barbariee37300e2017-06-08 11:22:16 -0400149 kafka_client_output = run_long_running_command_with_timeout(cmd, 30)
Stephane Barbarie52198b92017-03-02 13:44:46 -0500150
151 # Verify the kafka client output
152 found = False
Stephane Barbariee37300e2017-06-08 11:22:16 -0400153 alarm_data = None
Stephane Barbarie52198b92017-03-02 13:44:46 -0500154
155 for out in kafka_client_output:
Stephane Barbariee37300e2017-06-08 11:22:16 -0400156 # Catch any error that might occur while reading the kafka messages
157 try:
158 alarm_data = simplejson.loads(out)
159 print alarm_data
Stephane Barbarie52198b92017-03-02 13:44:46 -0500160
Stephane Barbariee37300e2017-06-08 11:22:16 -0400161 if not alarm_data or 'resource_id' not in alarm_data:
162 continue
163 elif alarm_data['resource_id'] == device_id:
164 found = True
165 break
Stephane Barbarie52198b92017-03-02 13:44:46 -0500166
Stephane Barbariee37300e2017-06-08 11:22:16 -0400167 except Exception as e:
Stephane Barbarie52198b92017-03-02 13:44:46 -0500168 continue
Stephane Barbarie52198b92017-03-02 13:44:46 -0500169
Stephane Barbariecc6b2e62017-03-02 14:35:55 -0500170 self.assertTrue(
171 found,
172 'Failed to find kafka alarm with device id:{}'.format(device_id))
Stephane Barbarie52198b92017-03-02 13:44:46 -0500173
Stephane Barbariee37300e2017-06-08 11:22:16 -0400174 return alarm_data
Stephane Barbarie52198b92017-03-02 13:44:46 -0500175
176 # Verify that the alarm follows the proper schema structure
177 def validate_alarm_event_schema(self, alarm):
178 try:
179 jsonschema.validate(alarm, ALARM_SCHEMA)
180 except Exception as e:
Stephane Barbariecc6b2e62017-03-02 14:35:55 -0500181 self.assertTrue(
182 False, 'Validation failed for alarm : {}'.format(e.message))
Stephane Barbarie52198b92017-03-02 13:44:46 -0500183
184 # Verify that alarm identifier based on the format generated by default.
185 def verify_alarm_event_id(self, device_id, alarm_id):
186 prefix = re.findall(r"(voltha)\.(\w+)\.(\w+)", alarm_id)
187
Stephane Barbariecc6b2e62017-03-02 14:35:55 -0500188 self.assertEqual(
189 len(prefix), 1,
190 'Failed to parse the alarm id: {}'.format(alarm_id))
191 self.assertEqual(
192 len(prefix[0]), 3,
193 'Expected id format: voltha.<adapter name>.<device id>')
194 self.assertEqual(
195 prefix[0][0], 'voltha',
196 'Expected id format: voltha.<adapter name>.<device id>')
197 self.assertEqual(
198 prefix[0][1], 'simulated_olt',
199 'Expected id format: voltha.<adapter name>.<device id>')
200 self.assertEqual(
201 prefix[0][2], device_id,
202 'Expected id format: voltha.<adapter name>.<device id>')
Stephane Barbarie52198b92017-03-02 13:44:46 -0500203
204
205if __name__ == '__main__':
206 main()