blob: c436d137cc52c536e73bb7e58778482d5ad5a928 [file] [log] [blame]
Scott Bakere27de6a2017-11-28 17:10:08 -08001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
17import unittest
18from mock import patch, call, Mock, MagicMock, PropertyMock
19import mock
20
21import os, sys
22
23test_path=os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
24service_dir=os.path.join(test_path, "../../../..")
25xos_dir=os.path.join(test_path, "../../..")
26if not os.path.exists(os.path.join(test_path, "new_base")):
27 xos_dir=os.path.join(test_path, "../../../../../../orchestration/xos/xos")
28 services_dir=os.path.join(xos_dir, "../../xos_services")
29
30class TestSyncVSGServiceInstance(unittest.TestCase):
31 def setUp(self):
32 global SyncVSGServiceInstance, LeastLoadedNodeScheduler, MockObjectList
33
34 self.sys_path_save = sys.path
35 sys.path.append(xos_dir)
36 sys.path.append(os.path.join(xos_dir, 'synchronizers', 'new_base'))
37
38 config = os.path.join(test_path, "test_config.yaml")
39 from xosconfig import Config
40 Config.clear()
41 Config.init(config, 'synchronizer-config-schema.yaml')
42
43 from synchronizers.new_base.mock_modelaccessor_build import build_mock_modelaccessor
44 build_mock_modelaccessor(xos_dir, services_dir, ["vsg/xos/vsg.xproto", "addressmanager/xos/addressmanager.xproto"])
45
46 import synchronizers.new_base.modelaccessor
47 import synchronizers.new_base.model_policies.model_policy_tenantwithcontainer
48 import sync_vsgserviceinstance
49 from sync_vsgserviceinstance import SyncVSGServiceInstance, model_accessor
50
51 from mock_modelaccessor import MockObjectList
52
53 # import all class names to globals
54 for (k, v) in model_accessor.all_model_classes.items():
55 globals()[k] = v
56
57 # Some of the functions we call have side-effects. For example, creating a VSGServiceInstance may lead to creation of
58 # tags. Ideally, this wouldn't happen, but it does. So make sure we reset the world.
59 model_accessor.reset_all_object_stores()
60
61 # attic functions that are not present in the mock model accessor
62 AddressManagerServiceInstance.set_attribute = Mock()
63
64 self.syncstep = SyncVSGServiceInstance()
65
66 # set up an object hierarchy that represents a Service and ServiceInstance
67
68 self.user = User(email="testadmin@test.org")
69 self.service = VSGService(name="the_vsg_service",
70 id=1,
71 docker_image_name="reg/vsg_docker",
72 docker_insecure_registry=True,
73 dns_servers="dnsone,dnstwo",
74 url_filter_kind=None,
75 private_key_fn=os.path.join(test_path, "test_private_key"))
76 self.subscriber = MagicMock(firewall_rules = "rule1",
77 firewall_enable = True,
78 url_filter_enable = True,
79 url_filter_level="R",
80 cdn_enable=True,
81 uplink_speed=1234,
82 downlink_speed=5678,
83 enable_uverse=False,
84 status="suspended",
85 sync_attributes=["firewall_rules", "firewall_enable", "url_filter_enable",
86 "url_filter_level", "cdn_enable", "uplink_speed",
87 "downlink_speed", "enable_uverse", "status"])
88 self.volt = MagicMock(s_tag=111, c_tag=222, subscriber=self.subscriber)
89 self.tenant = VSGServiceInstance(creator=self.user,
90 id=401,
91 volt=self.volt,
92 owner=self.service,
93 wan_container_ip="10.7.1.3",
94 wan_container_netbits="24",
95 wan_container_mac="02:42:0a:07:01:03",
96 wan_container_gateway_ip="10.7.1.1",
97 wan_vm_ip="10.7.1.2",
98 wan_vm_mac="02:42:0a:07:01:02",
99 sync_attributes = ["wan_container_ip", "wan_container_netbits", "wan_container_mac",
100 "wan_container_gateway_ip", "wan_vm_ip", "wan_vm_mac"])
101 self.flavor = Flavor(name="m1.small")
102 self.npt_ctag = NetworkParameterType(name="c_tag", id=1)
103 self.npt_stag = NetworkParameterType(name="s_tag", id=2)
104 self.npt_neutron_port_name = NetworkParameterType(name="neutron_port_name", id=501)
105 self.priv_template = NetworkTemplate(name="access_network", visibility="private")
106 self.priv_network = Network(name="mysite_test1_private", template=self.priv_template)
107 self.image = Image(name="trusty-server-multi-nic")
108 self.deployment = Deployment(name="testdeployment")
109 self.user = User(email="smbaker", id=701)
110 self.controller = Controller(id=101)
111 self.node = Node(name="testnode")
112 self.slice = Slice(name="mysite_test1", default_flavor=self.flavor, default_isolation="vm", service=self.service, id=301)
113 self.instance = Instance(slice=self.slice,
114 instance_name="testinstance1_instance_name",
115 instance_id="testinstance1_instance_id",
116 name="testinstance1_name",
117 node=self.node,
118 creator=self.user,
119 controller=self.controller)
120 self.tenant.instance = self.instance
121 self.instance.get_ssh_ip = Mock(return_value="1.2.3.4")
122 self.controllerslice = ControllerSlice(slice_id=self.slice.id, controller_id=self.controller.id, id=201)
123 self.controlleruser = ControllerUser(user_id=self.user.id, controller_id=self.controller.id, id=601)
124
125 def tearDown(self):
126 sys.path = self.sys_path_save
127
128 def test_get_vsg_service(self):
129 with patch.object(VSGService.objects, "get_items") as vsgservice_objects:
130 vsgservice_objects.return_value = [self.service]
131
132 self.tenant.owner = self.service
133
134 self.assertEqual(self.syncstep.get_vsg_service(self.tenant), self.service)
135
136 def test_get_extra_attributes(self):
137 with patch.object(VSGService.objects, "get_items") as vsgservice_objects:
138 vsgservice_objects.return_value = [self.service]
139
140 attrs = self.syncstep.get_extra_attributes(self.tenant)
141
142 desired_attrs = {"s_tags": [111],
143 "c_tags": [222],
144 "docker_remote_image_name": "reg/vsg_docker",
145 "docker_local_image_name": "reg/vsg_docker",
146 "docker_opts": "--insecure-registry reg",
147 "dnsdemux_ip": "none",
148 "cdn_prefixes": [],
149 "full_setup": True,
150 "isolation": "vm",
151 "safe_browsing_macs": [],
152 "container_name": "vsg-111-222",
153 "dns_servers": ["dnsone", "dnstwo"],
154 "url_filter_kind": None,
155
156 "firewall_rules": "rule1",
157 "firewall_enable": True,
158 "url_filter_enable": True,
159 "url_filter_level": "R",
160 "cdn_enable": True,
161 "uplink_speed": 1234,
162 "downlink_speed": 5678,
163 "enable_uverse": False,
164 "status": "suspended"}
165
166 self.assertDictContainsSubset(desired_attrs, attrs)
167
168
169 def test_sync_record(self):
170 with patch.object(VSGService.objects, "get_items") as vsgservice_objects, \
171 patch.object(Slice.objects, "get_items") as slice_objects, \
172 patch.object(User.objects, "get_items") as user_objects, \
173 patch.object(ControllerSlice.objects, "get_items") as controllerslice_objects, \
174 patch.object(ControllerUser.objects, "get_items") as controlleruser_objects, \
175 patch.object(SyncVSGServiceInstance, "run_playbook") as run_playbook:
176 slice_objects.return_value = [self.slice]
177 vsgservice_objects.return_value = [self.service]
178 controllerslice_objects.return_value = [self.controllerslice]
179 controlleruser_objects.return_value = [self.controlleruser]
180 user_objects.return_value = [self.user]
181
182 self.tenant.updated = 10
183 self.tenant.policed = 20
184 self.tenant.enacted = None
185
186 run_playbook.return_value = True
187
188 self.syncstep.sync_record(self.tenant)
189
190 run_playbook.assert_called()
191
192 attrs = run_playbook.call_args[0][1]
193
194 desired_attrs = {"username": "ubuntu",
195 "ansible_tag": "VSGServiceInstance_401",
196 "instance_name": "testinstance1_name",
197 "hostname": "testnode",
198 "private_key": "some_key\n",
199 "ssh_ip": "1.2.3.4",
200 "instance_id": "testinstance1_instance_id",
201
202 "wan_container_ip": "10.7.1.3",
203 "wan_container_netbits": "24",
204 "wan_container_mac": "02:42:0a:07:01:03",
205 "wan_container_gateway_ip": "10.7.1.1",
206 "wan_vm_ip": "10.7.1.2",
207 "wan_vm_mac": "02:42:0a:07:01:02",
208
209 "s_tags": [111],
210 "c_tags": [222],
211 "docker_remote_image_name": "reg/vsg_docker",
212 "docker_local_image_name": "reg/vsg_docker",
213 "docker_opts": "--insecure-registry reg",
214 "dnsdemux_ip": "none",
215 "cdn_prefixes": [],
216 "full_setup": True,
217 "isolation": "vm",
218 "safe_browsing_macs": [],
219 "container_name": "vsg-111-222",
220 "dns_servers": ["dnsone", "dnstwo"],
221 "url_filter_kind": None,
222
223 "firewall_rules": "rule1",
224 "firewall_enable": True,
225 "url_filter_enable": True,
226 "url_filter_level": "R",
227 "cdn_enable": True,
228 "uplink_speed": 1234,
229 "downlink_speed": 5678,
230 "enable_uverse": False,
231 "status": "suspended"}
232
233 self.assertDictContainsSubset(desired_attrs, attrs)
234
235 def test_sync_record_emptysubscriber(self):
236 with patch.object(VSGService.objects, "get_items") as vsgservice_objects, \
237 patch.object(Slice.objects, "get_items") as slice_objects, \
238 patch.object(User.objects, "get_items") as user_objects, \
239 patch.object(ControllerSlice.objects, "get_items") as controllerslice_objects, \
240 patch.object(ControllerUser.objects, "get_items") as controlleruser_objects, \
241 patch.object(SyncVSGServiceInstance, "run_playbook") as run_playbook:
242 slice_objects.return_value = [self.slice]
243 vsgservice_objects.return_value = [self.service]
244 controllerslice_objects.return_value = [self.controllerslice]
245 controlleruser_objects.return_value = [self.controlleruser]
246 user_objects.return_value = [self.user]
247
248 self.tenant.updated = 10
249 self.tenant.policed = 20
250 self.tenant.enacted = None
251
252 self.volt.subscriber = MagicMock()
253
254 run_playbook.return_value = True
255
256 self.syncstep.sync_record(self.tenant)
257
258 run_playbook.assert_called()
259
260 attrs = run_playbook.call_args[0][1]
261
262 desired_attrs = {"firewall_rules": "",
263 "firewall_enable": False,
264 "url_filter_enable": False,
265 "url_filter_level": "PG",
266 "cdn_enable": False,
267 "uplink_speed": 1000000000,
268 "downlink_speed": 1000000000,
269 "enable_uverse": True,
270 "status": "enabled"}
271
272 self.assertDictContainsSubset(desired_attrs, attrs)
273
274 def test_sync_record_no_policy(self):
275 with patch.object(SyncVSGServiceInstance, "run_playbook") as run_playbook:
276
277 self.tenant.updated = 10
278 self.tenant.policed = 5 # policies need to be run
279 self.tenant.enacted = None
280
281 with self.assertRaises(Exception) as e:
282 self.syncstep.sync_record(self.tenant)
283 self.assertIn("due to waiting on model policy", e.exception.message)
284
285 run_playbook.assert_not_called()
286
287 def test_sync_record_instance_not_ready(self):
288 with patch.object(SyncVSGServiceInstance, "run_playbook") as run_playbook:
289
290 self.tenant.updated = 10
291 self.tenant.policed = 20
292 self.tenant.enacted = None
293
294 self.instance.instance_name = None # no instance_name means instance is not ready
295
296 with self.assertRaises(Exception) as e:
297 self.syncstep.sync_record(self.tenant)
298 self.assertIn("due to waiting on instance.instance_name", e.exception.message)
299
300 run_playbook.assert_not_called()
301
302 def test_delete_record_no_policy(self):
303 self.tenant.updated = 10
304 self.tenant.policed = 20
305 self.tenant.enacted = None
306
307 self.syncstep.delete_record(self.tenant)
308
309 # delete doesn't actually do anything, so nothing to further test.
310
311 def test_delete_record_no_policy(self):
312 self.tenant.updated = 10
313 self.tenant.policed = 5 # policies need to be run
314 self.tenant.enacted = None
315
316 with self.assertRaises(Exception) as e:
317 self.syncstep.delete_record(self.tenant)
318 self.assertIn("due to waiting on model policy", e.exception.message)
319
320if __name__ == '__main__':
321 unittest.main()
322
323