blob: 05d83f6489a0fe888a743a1aefe9eed0e3c20ead [file] [log] [blame]
Scott Baker5bbdcac2017-11-29 11:39:24 -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 TestSyncVEGServiceInstance(unittest.TestCase):
31 def setUp(self):
32 global SyncVEGTenant, 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, ["vEG/xos/veg.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_vegtenant
49 from sync_vegtenant import SyncVEGTenant, 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 VEGTenant 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 = SyncVEGTenant()
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 = VEGService(name="the_veg_service",
70 id=1,
71 docker_image_name="reg/veg_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 # E-CORD / vEG doesn't support these subscriber fields at this time, but keep them in the test for now since the
77 # synchronizer supports them to maintain similarity with vSG. If/when E-CORD introduces its own subscriber
78 # object, deal with the differences here.
79 self.subscriber = MagicMock(firewall_rules = "rule1",
80 firewall_enable = True,
81 url_filter_enable = True,
82 url_filter_level="R",
83 cdn_enable=True,
84 uplink_speed=1234,
85 downlink_speed=5678,
86 enable_uverse=False,
87 status="suspended",
88 sync_attributes=["firewall_rules", "firewall_enable", "url_filter_enable",
89 "url_filter_level", "cdn_enable", "uplink_speed",
90 "downlink_speed", "enable_uverse", "status"])
91 self.volt = MagicMock(s_tag=111, c_tag=222, subscriber=self.subscriber)
92 self.tenant = VEGTenant(creator=self.user,
93 id=401,
94 volt=self.volt,
95 owner=self.service,
96 wan_container_ip="10.7.1.3",
97 wan_container_netbits="24",
98 wan_container_mac="02:42:0a:07:01:03",
99 wan_container_gateway_ip="10.7.1.1",
100 wan_vm_ip="10.7.1.2",
101 wan_vm_mac="02:42:0a:07:01:02",
102 sync_attributes = ["wan_container_ip", "wan_container_netbits", "wan_container_mac",
103 "wan_container_gateway_ip", "wan_vm_ip", "wan_vm_mac"])
104 self.flavor = Flavor(name="m1.small")
105 self.npt_ctag = NetworkParameterType(name="c_tag", id=1)
106 self.npt_stag = NetworkParameterType(name="s_tag", id=2)
107 self.npt_neutron_port_name = NetworkParameterType(name="neutron_port_name", id=501)
108 self.priv_template = NetworkTemplate(name="access_network", visibility="private")
109 self.priv_network = Network(name="mysite_test1_private", template=self.priv_template)
110 self.image = Image(name="trusty-server-multi-nic")
111 self.deployment = Deployment(name="testdeployment")
112 self.user = User(email="smbaker", id=701)
113 self.controller = Controller(id=101)
114 self.node = Node(name="testnode")
115 self.slice = Slice(name="mysite_test1", default_flavor=self.flavor, default_isolation="vm", service=self.service, id=301)
116 self.instance = Instance(slice=self.slice,
117 instance_name="testinstance1_instance_name",
118 instance_id="testinstance1_instance_id",
119 name="testinstance1_name",
120 node=self.node,
121 creator=self.user,
122 controller=self.controller)
123 self.tenant.instance = self.instance
124 self.instance.get_ssh_ip = Mock(return_value="1.2.3.4")
125 self.controllerslice = ControllerSlice(slice_id=self.slice.id, controller_id=self.controller.id, id=201)
126 self.controlleruser = ControllerUser(user_id=self.user.id, controller_id=self.controller.id, id=601)
127
128 def tearDown(self):
129 sys.path = self.sys_path_save
130
131 def test_get_veg_service(self):
132 with patch.object(VEGService.objects, "get_items") as vegservice_objects:
133 vegservice_objects.return_value = [self.service]
134
135 self.tenant.owner = self.service
136
137 self.assertEqual(self.syncstep.get_veg_service(self.tenant), self.service)
138
139 def test_get_extra_attributes(self):
140 with patch.object(VEGService.objects, "get_items") as vegservice_objects:
141 vegservice_objects.return_value = [self.service]
142
143 attrs = self.syncstep.get_extra_attributes(self.tenant)
144
145 desired_attrs = {"s_tags": [111],
146 "c_tags": [222],
147 "docker_remote_image_name": "reg/veg_docker",
148 "docker_local_image_name": "reg/veg_docker",
149 "docker_opts": "--insecure-registry reg",
150 "dnsdemux_ip": "none",
151 "cdn_prefixes": [],
152 "full_setup": True,
153 "isolation": "vm",
154 "safe_browsing_macs": [],
155 "container_name": "veg-111-222",
156 "dns_servers": ["dnsone", "dnstwo"],
157 "url_filter_kind": None,
158
159 "firewall_rules": "rule1",
160 "firewall_enable": True,
161 "url_filter_enable": True,
162 "url_filter_level": "R",
163 "cdn_enable": True,
164 "uplink_speed": 1234,
165 "downlink_speed": 5678,
166 "enable_uverse": False,
167 "status": "suspended"}
168
169 self.assertDictContainsSubset(desired_attrs, attrs)
170
171
172 def test_sync_record(self):
173 with patch.object(VEGService.objects, "get_items") as vegservice_objects, \
174 patch.object(Slice.objects, "get_items") as slice_objects, \
175 patch.object(User.objects, "get_items") as user_objects, \
176 patch.object(ControllerSlice.objects, "get_items") as controllerslice_objects, \
177 patch.object(ControllerUser.objects, "get_items") as controlleruser_objects, \
178 patch.object(SyncVEGTenant, "run_playbook") as run_playbook:
179 slice_objects.return_value = [self.slice]
180 vegservice_objects.return_value = [self.service]
181 controllerslice_objects.return_value = [self.controllerslice]
182 controlleruser_objects.return_value = [self.controlleruser]
183 user_objects.return_value = [self.user]
184
185 self.tenant.updated = 10
186 self.tenant.policed = 20
187 self.tenant.enacted = None
188
189 run_playbook.return_value = True
190
191 self.syncstep.sync_record(self.tenant)
192
193 run_playbook.assert_called()
194
195 attrs = run_playbook.call_args[0][1]
196
197 desired_attrs = {"username": "ubuntu",
198 "ansible_tag": "VEGTenant_401",
199 "instance_name": "testinstance1_name",
200 "hostname": "testnode",
201 "private_key": "some_key\n",
202 "ssh_ip": "1.2.3.4",
203 "instance_id": "testinstance1_instance_id",
204
205 "wan_container_ip": "10.7.1.3",
206 "wan_container_netbits": "24",
207 "wan_container_mac": "02:42:0a:07:01:03",
208 "wan_container_gateway_ip": "10.7.1.1",
209 "wan_vm_ip": "10.7.1.2",
210 "wan_vm_mac": "02:42:0a:07:01:02",
211
212 "s_tags": [111],
213 "c_tags": [222],
214 "docker_remote_image_name": "reg/veg_docker",
215 "docker_local_image_name": "reg/veg_docker",
216 "docker_opts": "--insecure-registry reg",
217 "dnsdemux_ip": "none",
218 "cdn_prefixes": [],
219 "full_setup": True,
220 "isolation": "vm",
221 "safe_browsing_macs": [],
222 "container_name": "veg-111-222",
223 "dns_servers": ["dnsone", "dnstwo"],
224 "url_filter_kind": None,
225
226 "firewall_rules": "rule1",
227 "firewall_enable": True,
228 "url_filter_enable": True,
229 "url_filter_level": "R",
230 "cdn_enable": True,
231 "uplink_speed": 1234,
232 "downlink_speed": 5678,
233 "enable_uverse": False,
234 "status": "suspended"}
235
236 self.assertDictContainsSubset(desired_attrs, attrs)
237
238 def test_sync_record_emptysubscriber(self):
239 with patch.object(VEGService.objects, "get_items") as vegservice_objects, \
240 patch.object(Slice.objects, "get_items") as slice_objects, \
241 patch.object(User.objects, "get_items") as user_objects, \
242 patch.object(ControllerSlice.objects, "get_items") as controllerslice_objects, \
243 patch.object(ControllerUser.objects, "get_items") as controlleruser_objects, \
244 patch.object(SyncVEGTenant, "run_playbook") as run_playbook:
245 slice_objects.return_value = [self.slice]
246 vegservice_objects.return_value = [self.service]
247 controllerslice_objects.return_value = [self.controllerslice]
248 controlleruser_objects.return_value = [self.controlleruser]
249 user_objects.return_value = [self.user]
250
251 self.tenant.updated = 10
252 self.tenant.policed = 20
253 self.tenant.enacted = None
254
255 self.volt.subscriber = MagicMock()
256
257 run_playbook.return_value = True
258
259 self.syncstep.sync_record(self.tenant)
260
261 run_playbook.assert_called()
262
263 attrs = run_playbook.call_args[0][1]
264
265 desired_attrs = {"firewall_rules": "",
266 "firewall_enable": False,
267 "url_filter_enable": False,
268 "url_filter_level": "PG",
269 "cdn_enable": False,
270 "uplink_speed": 1000000000,
271 "downlink_speed": 1000000000,
272 "enable_uverse": True,
273 "status": "enabled"}
274
275 self.assertDictContainsSubset(desired_attrs, attrs)
276
277 def test_sync_record_no_policy(self):
278 with patch.object(SyncVEGTenant, "run_playbook") as run_playbook:
279
280 self.tenant.updated = 10
281 self.tenant.policed = 5 # policies need to be run
282 self.tenant.enacted = None
283
284 with self.assertRaises(Exception) as e:
285 self.syncstep.sync_record(self.tenant)
286 self.assertIn("due to waiting on model policy", e.exception.message)
287
288 run_playbook.assert_not_called()
289
290 def test_sync_record_instance_not_ready(self):
291 with patch.object(SyncVEGTenant, "run_playbook") as run_playbook:
292
293 self.tenant.updated = 10
294 self.tenant.policed = 20
295 self.tenant.enacted = None
296
297 self.instance.instance_name = None # no instance_name means instance is not ready
298
299 with self.assertRaises(Exception) as e:
300 self.syncstep.sync_record(self.tenant)
301 self.assertIn("due to waiting on instance.instance_name", e.exception.message)
302
303 run_playbook.assert_not_called()
304
305 def test_delete_record_no_policy(self):
306 self.tenant.updated = 10
307 self.tenant.policed = 20
308 self.tenant.enacted = None
309
310 self.syncstep.delete_record(self.tenant)
311
312 # delete doesn't actually do anything, so nothing to further test.
313
314 def test_delete_record_no_policy(self):
315 self.tenant.updated = 10
316 self.tenant.policed = 5 # policies need to be run
317 self.tenant.enacted = None
318
319 with self.assertRaises(Exception) as e:
320 self.syncstep.delete_record(self.tenant)
321 self.assertIn("due to waiting on model policy", e.exception.message)
322
323if __name__ == '__main__':
324 unittest.main()
325
326