Merge lp:~jameinel/maas/1.2-remove-kernel-opts into lp:maas/trunk
- 1.2-remove-kernel-opts
- Merge into trunk
Proposed by
John A Meinel
on 2012-11-08
| Status: | Superseded |
|---|---|
| Proposed branch: | lp:~jameinel/maas/1.2-remove-kernel-opts |
| Merge into: | lp:maas/trunk |
| Diff against target: |
601 lines (+378/-33) (has conflicts) 11 files modified
src/maasserver/api.py (+16/-3) src/maasserver/forms.py (+13/-0) src/maasserver/templates/maasserver/node_list.html (+5/-0) src/maasserver/tests/test_api.py (+56/-0) src/maasserver/tests/test_forms.py (+75/-30) src/maasserver/tests/test_views_nodes.py (+60/-0) src/maasserver/utils/__init__.py (+25/-0) src/maasserver/utils/tests/test_utils.py (+78/-0) src/provisioningserver/boot_images.py (+4/-0) src/provisioningserver/tasks.py (+16/-0) src/provisioningserver/tests/test_tasks.py (+30/-0) Text conflict in src/maasserver/api.py Text conflict in src/maasserver/forms.py Text conflict in src/maasserver/templates/maasserver/node_list.html Text conflict in src/maasserver/tests/test_api.py Text conflict in src/maasserver/tests/test_forms.py Text conflict in src/maasserver/tests/test_views_nodes.py Text conflict in src/maasserver/utils/__init__.py Text conflict in src/maasserver/utils/tests/test_utils.py Text conflict in src/provisioningserver/boot_images.py Text conflict in src/provisioningserver/tasks.py Text conflict in src/provisioningserver/tests/test_tasks.py |
| To merge this branch: | bzr merge lp:~jameinel/maas/1.2-remove-kernel-opts |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Launchpad code reviewers | 2012-11-08 | Pending | |
|
Review via email:
|
|||
This proposal has been superseded by a proposal from 2012-11-08.
Commit Message
This removes the recent patches to add kernel_opts to the 1.2 branch.
We'll land it instead on trunk, and then it will get backported in the future once a bugfix only SRU was done.
Description of the Change
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === modified file 'etc/celeryconfig_common.py' |
| 2 | === modified file 'src/maasserver/api.py' |
| 3 | --- src/maasserver/api.py 2012-11-08 09:12:44 +0000 |
| 4 | +++ src/maasserver/api.py 2012-11-08 09:19:27 +0000 |
| 5 | @@ -745,9 +745,22 @@ |
| 6 | |
| 7 | When a node has been added to MAAS by an admin MAAS user, it is |
| 8 | ready for allocation to services running on the MAAS. |
| 9 | - The minimum data required is: |
| 10 | - architecture=<arch string> (e.g "i386/generic") |
| 11 | - mac_address=<value> |
| 12 | +<<<<<<< TREE |
| 13 | + The minimum data required is: |
| 14 | + architecture=<arch string> (e.g "i386/generic") |
| 15 | + mac_address=<value> |
| 16 | +======= |
| 17 | + The minimum data required is: |
| 18 | + architecture=<arch string> (e.g "i386/generic") |
| 19 | + mac_address=<value> |
| 20 | + |
| 21 | + :param architecture: A string containing the architecture type of |
| 22 | + the node. |
| 23 | + :param mac_address: The MAC address of the node. |
| 24 | + :param hostname: A hostname. If not given, one will be generated. |
| 25 | + :param powertype: A power management type, if applicable (e.g. |
| 26 | + "virsh", "ipmi"). |
| 27 | +>>>>>>> MERGE-SOURCE |
| 28 | """ |
| 29 | node = create_node(request) |
| 30 | if request.user.is_superuser: |
| 31 | |
| 32 | === modified file 'src/maasserver/forms.py' |
| 33 | --- src/maasserver/forms.py 2012-11-01 15:13:10 +0000 |
| 34 | +++ src/maasserver/forms.py 2012-11-08 09:19:27 +0000 |
| 35 | @@ -394,6 +394,7 @@ |
| 36 | node.save() |
| 37 | for mac in self.cleaned_data['mac_addresses']: |
| 38 | node.add_mac_address(mac) |
| 39 | +<<<<<<< TREE |
| 40 | hostname = self.cleaned_data['hostname'] |
| 41 | stripped_hostname = strip_domain(hostname) |
| 42 | # Generate a hostname for this node if the provided hostname is |
| 43 | @@ -404,6 +405,18 @@ |
| 44 | IP_BASED_HOSTNAME_REGEXP.match(stripped_hostname) != None) |
| 45 | if generate_hostname: |
| 46 | node.set_random_hostname() |
| 47 | +======= |
| 48 | + hostname = self.cleaned_data['hostname'] |
| 49 | + stripped_hostname = strip_domain(hostname) |
| 50 | + # Generate a hostname for this node if the provided hostname is |
| 51 | + # IP-based (because this means that this name comes from a DNS |
| 52 | + # reverse query to the MAAS DNS) or an empty string. |
| 53 | + generate_hostname = ( |
| 54 | + hostname == "" or |
| 55 | + IP_BASED_HOSTNAME_REGEXP.match(stripped_hostname) != None) |
| 56 | + if generate_hostname: |
| 57 | + node.set_mac_based_hostname(self.cleaned_data['mac_addresses'][0]) |
| 58 | +>>>>>>> MERGE-SOURCE |
| 59 | return node |
| 60 | |
| 61 | |
| 62 | |
| 63 | === modified file 'src/maasserver/models/node.py' |
| 64 | === modified file 'src/maasserver/models/nodegroup.py' |
| 65 | === modified file 'src/maasserver/templates/maasserver/node_list.html' |
| 66 | --- src/maasserver/templates/maasserver/node_list.html 2012-10-24 12:51:10 +0000 |
| 67 | +++ src/maasserver/templates/maasserver/node_list.html 2012-11-08 09:19:27 +0000 |
| 68 | @@ -38,8 +38,13 @@ |
| 69 | {% if input_query_error %} |
| 70 | <p class="form-errors">{{input_query_error}}</p> |
| 71 | {% endif %} |
| 72 | +<<<<<<< TREE |
| 73 | {% include "maasserver/nodes_listing.html" with sorting="true" %} |
| 74 | {% include "maasserver/pagination.html" %} |
| 75 | +======= |
| 76 | + {% include "maasserver/nodes_listing.html" %} |
| 77 | + {% include "maasserver/pagination.html" %} |
| 78 | +>>>>>>> MERGE-SOURCE |
| 79 | <a id="addnode" href="#" class="button right space-top">+ Add node</a> |
| 80 | <div class="clear"></div> |
| 81 | <a class="right space-top" href="{% url "enlist-preseed-view" %}">View enlistment preseed</a> |
| 82 | |
| 83 | === modified file 'src/maasserver/testing/factory.py' |
| 84 | === modified file 'src/maasserver/tests/test_api.py' |
| 85 | --- src/maasserver/tests/test_api.py 2012-11-08 09:12:44 +0000 |
| 86 | +++ src/maasserver/tests/test_api.py 2012-11-08 09:19:27 +0000 |
| 87 | @@ -122,11 +122,18 @@ |
| 88 | NodeUserData, |
| 89 | ) |
| 90 | from metadataserver.nodeinituser import get_node_init_user |
| 91 | +<<<<<<< TREE |
| 92 | from mock import ( |
| 93 | ANY, |
| 94 | call, |
| 95 | Mock, |
| 96 | ) |
| 97 | +======= |
| 98 | +from mock import ( |
| 99 | + ANY, |
| 100 | + Mock, |
| 101 | + ) |
| 102 | +>>>>>>> MERGE-SOURCE |
| 103 | from provisioningserver import ( |
| 104 | boot_images, |
| 105 | kernel_opts, |
| 106 | @@ -4433,6 +4440,7 @@ |
| 107 | self.assertSetEqual( |
| 108 | {"doc", "handlers", "resources"}, set(description)) |
| 109 | self.assertIsInstance(description["handlers"], list) |
| 110 | +<<<<<<< TREE |
| 111 | |
| 112 | |
| 113 | class TestDescribeAbsoluteURIs(AnonAPITestCase): |
| 114 | @@ -4513,3 +4521,51 @@ |
| 115 | resources = description["resources"] |
| 116 | self.assertNotEqual([], resources) |
| 117 | self.assertThat(resources, AllMatch(expected_resource)) |
| 118 | +======= |
| 119 | + |
| 120 | + |
| 121 | +class TestDescribeAbsoluteURIs(AnonAPITestCase): |
| 122 | + """Tests for the `describe` view's URI manipulation.""" |
| 123 | + |
| 124 | + scenarios_schemes = ( |
| 125 | + ("http", dict(scheme="http")), |
| 126 | + ("https", dict(scheme="https")), |
| 127 | + ) |
| 128 | + |
| 129 | + scenarios_paths = ( |
| 130 | + ("script-at-root", dict(script_name="", path_info="")), |
| 131 | + ("script-below-root-1", dict(script_name="/foo/bar", path_info="")), |
| 132 | + ("script-below-root-2", dict(script_name="/foo", path_info="/bar")), |
| 133 | + ) |
| 134 | + |
| 135 | + scenarios = multiply_scenarios( |
| 136 | + scenarios_schemes, scenarios_paths) |
| 137 | + |
| 138 | + def test_handler_uris_are_absolute(self): |
| 139 | + server = factory.make_name("server").lower() |
| 140 | + extra = { |
| 141 | + "PATH_INFO": self.path_info, |
| 142 | + "SCRIPT_NAME": self.script_name, |
| 143 | + "SERVER_NAME": server, |
| 144 | + "wsgi.url_scheme": self.scheme, |
| 145 | + } |
| 146 | + request = RequestFactory().get( |
| 147 | + "/%s/describe" % factory.make_name("path"), **extra) |
| 148 | + response = describe(request) |
| 149 | + self.assertEqual(httplib.OK, response.status_code, response.content) |
| 150 | + description = json.loads(response.content) |
| 151 | + expected_uri = AfterPreprocessing( |
| 152 | + urlparse, MatchesStructure( |
| 153 | + scheme=Equals(self.scheme), hostname=Equals(server), |
| 154 | + # The path is always the script name followed by "api/" |
| 155 | + # because all API calls are within the "api" tree. |
| 156 | + path=StartsWith(self.script_name + "/api/"))) |
| 157 | + expected_handler = MatchesAny( |
| 158 | + Is(None), AfterPreprocessing(itemgetter("uri"), expected_uri)) |
| 159 | + expected_resource = MatchesAll( |
| 160 | + AfterPreprocessing(itemgetter("anon"), expected_handler), |
| 161 | + AfterPreprocessing(itemgetter("auth"), expected_handler)) |
| 162 | + resources = description["resources"] |
| 163 | + self.assertNotEqual([], resources) |
| 164 | + self.assertThat(resources, AllMatch(expected_resource)) |
| 165 | +>>>>>>> MERGE-SOURCE |
| 166 | |
| 167 | === modified file 'src/maasserver/tests/test_dhcplease.py' |
| 168 | === modified file 'src/maasserver/tests/test_forms.py' |
| 169 | --- src/maasserver/tests/test_forms.py 2012-11-01 11:11:48 +0000 |
| 170 | +++ src/maasserver/tests/test_forms.py 2012-11-08 09:19:27 +0000 |
| 171 | @@ -350,36 +350,81 @@ |
| 172 | after_commissioning_action, node.after_commissioning_action) |
| 173 | self.assertEqual(power_type, node.power_type) |
| 174 | |
| 175 | - def test_AdminNodeForm_refuses_to_update_hostname_on_allocated_node(self): |
| 176 | - old_name = factory.make_name('old-hostname') |
| 177 | - new_name = factory.make_name('new-hostname') |
| 178 | - node = factory.make_node( |
| 179 | - hostname=old_name, status=NODE_STATUS.ALLOCATED) |
| 180 | - form = AdminNodeForm( |
| 181 | - data={ |
| 182 | - 'hostname': new_name, |
| 183 | - 'architecture': node.architecture, |
| 184 | - }, |
| 185 | - instance=node) |
| 186 | - self.assertFalse(form.is_valid()) |
| 187 | - self.assertEqual( |
| 188 | - ["Can't change hostname to %s: node is in use." % new_name], |
| 189 | - form._errors['hostname']) |
| 190 | - |
| 191 | - def test_AdminNodeForm_accepts_unchanged_hostname_on_allocated_node(self): |
| 192 | - old_name = factory.make_name('old-hostname') |
| 193 | - node = factory.make_node( |
| 194 | - hostname=old_name, status=NODE_STATUS.ALLOCATED) |
| 195 | - form = AdminNodeForm( |
| 196 | - data={ |
| 197 | - 'hostname': old_name, |
| 198 | - 'architecture': node.architecture, |
| 199 | - }, |
| 200 | - instance=node) |
| 201 | - self.assertTrue(form.is_valid(), form._errors) |
| 202 | - form.save() |
| 203 | - self.assertEqual(old_name, reload_object(node).hostname) |
| 204 | - |
| 205 | +<<<<<<< TREE |
| 206 | + def test_AdminNodeForm_refuses_to_update_hostname_on_allocated_node(self): |
| 207 | + old_name = factory.make_name('old-hostname') |
| 208 | + new_name = factory.make_name('new-hostname') |
| 209 | + node = factory.make_node( |
| 210 | + hostname=old_name, status=NODE_STATUS.ALLOCATED) |
| 211 | + form = AdminNodeForm( |
| 212 | + data={ |
| 213 | + 'hostname': new_name, |
| 214 | + 'architecture': node.architecture, |
| 215 | + }, |
| 216 | + instance=node) |
| 217 | + self.assertFalse(form.is_valid()) |
| 218 | + self.assertEqual( |
| 219 | + ["Can't change hostname to %s: node is in use." % new_name], |
| 220 | + form._errors['hostname']) |
| 221 | + |
| 222 | + def test_AdminNodeForm_accepts_unchanged_hostname_on_allocated_node(self): |
| 223 | + old_name = factory.make_name('old-hostname') |
| 224 | + node = factory.make_node( |
| 225 | + hostname=old_name, status=NODE_STATUS.ALLOCATED) |
| 226 | + form = AdminNodeForm( |
| 227 | + data={ |
| 228 | + 'hostname': old_name, |
| 229 | + 'architecture': node.architecture, |
| 230 | + }, |
| 231 | + instance=node) |
| 232 | + self.assertTrue(form.is_valid(), form._errors) |
| 233 | + form.save() |
| 234 | + self.assertEqual(old_name, reload_object(node).hostname) |
| 235 | + |
| 236 | +======= |
| 237 | + def test_AdminNodeForm_refuses_to_update_hostname_on_allocated_node(self): |
| 238 | + old_name = factory.make_name('old-hostname') |
| 239 | + new_name = factory.make_name('new-hostname') |
| 240 | + node = factory.make_node( |
| 241 | + hostname=old_name, status=NODE_STATUS.ALLOCATED) |
| 242 | + form = AdminNodeForm( |
| 243 | + data={ |
| 244 | + 'hostname': new_name, |
| 245 | + 'architecture': node.architecture, |
| 246 | + }, |
| 247 | + instance=node) |
| 248 | + self.assertFalse(form.is_valid()) |
| 249 | + self.assertEqual( |
| 250 | + ["Can't change hostname to %s: node is in use." % new_name], |
| 251 | + form._errors['hostname']) |
| 252 | + |
| 253 | + def test_AdminNodeForm_accepts_unchanged_hostname_on_allocated_node(self): |
| 254 | + old_name = factory.make_name('old-hostname') |
| 255 | + node = factory.make_node( |
| 256 | + hostname=old_name, status=NODE_STATUS.ALLOCATED) |
| 257 | + form = AdminNodeForm( |
| 258 | + data={ |
| 259 | + 'hostname': old_name, |
| 260 | + 'architecture': node.architecture, |
| 261 | + }, |
| 262 | + instance=node) |
| 263 | + self.assertTrue(form.is_valid(), form._errors) |
| 264 | + form.save() |
| 265 | + self.assertEqual(old_name, reload_object(node).hostname) |
| 266 | + |
| 267 | + def test_AdminNodeForm_accepts_omitted_hostname_on_allocated_node(self): |
| 268 | + node = factory.make_node(status=NODE_STATUS.ALLOCATED) |
| 269 | + old_name = node.hostname |
| 270 | + form = AdminNodeForm( |
| 271 | + data={ |
| 272 | + 'architecture': node.architecture, |
| 273 | + }, |
| 274 | + instance=node) |
| 275 | + self.assertTrue(form.is_valid()) |
| 276 | + form.save() |
| 277 | + self.assertEqual(old_name, reload_object(node).hostname) |
| 278 | + |
| 279 | +>>>>>>> MERGE-SOURCE |
| 280 | def test_remove_None_values_removes_None_values_in_dict(self): |
| 281 | random_input = factory.getRandomString() |
| 282 | self.assertEqual( |
| 283 | |
| 284 | === modified file 'src/maasserver/tests/test_node.py' |
| 285 | === modified file 'src/maasserver/tests/test_views_nodes.py' |
| 286 | --- src/maasserver/tests/test_views_nodes.py 2012-11-01 15:59:22 +0000 |
| 287 | +++ src/maasserver/tests/test_views_nodes.py 2012-11-08 09:19:27 +0000 |
| 288 | @@ -532,6 +532,7 @@ |
| 289 | "//div[@id='nodes']/table//td/a/@href") |
| 290 | self.assertEqual([node2_link], node_links) |
| 291 | |
| 292 | +<<<<<<< TREE |
| 293 | def test_node_list_paginates(self): |
| 294 | """Node listing is split across multiple pages with links""" |
| 295 | # Set a very small page size to save creating lots of nodes |
| 296 | @@ -591,6 +592,65 @@ |
| 297 | [(a.text.lower(), a.get("href")) |
| 298 | for a in document.xpath("//div[@class='pagination']//a")]) |
| 299 | |
| 300 | +======= |
| 301 | + def test_node_list_paginates(self): |
| 302 | + """Node listing is split across multiple pages with links""" |
| 303 | + # Set a very small page size to save creating lots of nodes |
| 304 | + page_size = 2 |
| 305 | + self.patch(nodes_views.NodeListView, 'paginate_by', page_size) |
| 306 | + nodes = [factory.make_node(created="2012-10-12 12:00:%02d" % i) |
| 307 | + for i in range(page_size * 2 + 1)] |
| 308 | + # Order node links with newest first as the view is expected to |
| 309 | + node_links = [reverse('node-view', args=[node.system_id]) |
| 310 | + for node in reversed(nodes)] |
| 311 | + expr_node_links = XPath("//div[@id='nodes']/table//a/@href") |
| 312 | + expr_page_anchors = XPath("//div[@class='pagination']//a") |
| 313 | + # Fetch first page, should link newest two nodes and page 2 |
| 314 | + response = self.client.get(reverse('node-list')) |
| 315 | + page1 = fromstring(response.content) |
| 316 | + self.assertEqual(node_links[:page_size], expr_node_links(page1)) |
| 317 | + self.assertEqual([("next", "?page=2"), ("last", "?page=3")], |
| 318 | + [(a.text.lower(), a.get("href")) |
| 319 | + for a in expr_page_anchors(page1)]) |
| 320 | + # Fetch second page, should link next nodes and adjacent pages |
| 321 | + response = self.client.get(reverse('node-list'), {"page": 2}) |
| 322 | + page2 = fromstring(response.content) |
| 323 | + self.assertEqual(node_links[page_size:page_size * 2], |
| 324 | + expr_node_links(page2)) |
| 325 | + self.assertEqual([("first", "."), ("previous", "."), |
| 326 | + ("next", "?page=3"), ("last", "?page=3")], |
| 327 | + [(a.text.lower(), a.get("href")) |
| 328 | + for a in expr_page_anchors(page2)]) |
| 329 | + # Fetch third page, should link oldest node and node list page |
| 330 | + response = self.client.get(reverse('node-list'), {"page": 3}) |
| 331 | + page3 = fromstring(response.content) |
| 332 | + self.assertEqual(node_links[page_size * 2:], expr_node_links(page3)) |
| 333 | + self.assertEqual([("first", "."), ("previous", "?page=2")], |
| 334 | + [(a.text.lower(), a.get("href")) |
| 335 | + for a in expr_page_anchors(page3)]) |
| 336 | + |
| 337 | + def test_node_list_query_paginates(self): |
| 338 | + """Node list query subset is split across multiple pages with links""" |
| 339 | + # Set a very small page size to save creating lots of nodes |
| 340 | + self.patch(nodes_views.NodeListView, 'paginate_by', 2) |
| 341 | + nodes = [factory.make_node(created="2012-10-12 12:00:%02d" % i) |
| 342 | + for i in range(10)] |
| 343 | + tag = factory.make_tag("odd") |
| 344 | + for node in nodes[::2]: |
| 345 | + node.tags = [tag] |
| 346 | + last_node_link = reverse('node-view', args=[nodes[0].system_id]) |
| 347 | + response = self.client.get(reverse('node-list'), |
| 348 | + {"query": "maas-tags=odd", "page": 3}) |
| 349 | + document = fromstring(response.content) |
| 350 | + self.assertIn("5 matching nodes", document.xpath("string(//h1)")) |
| 351 | + self.assertEqual([last_node_link], |
| 352 | + document.xpath("//div[@id='nodes']/table//a/@href")) |
| 353 | + self.assertEqual([("first", "?query=maas-tags%3Dodd"), |
| 354 | + ("previous", "?query=maas-tags%3Dodd&page=2")], |
| 355 | + [(a.text.lower(), a.get("href")) |
| 356 | + for a in document.xpath("//div[@class='pagination']//a")]) |
| 357 | + |
| 358 | +>>>>>>> MERGE-SOURCE |
| 359 | |
| 360 | class NodePreseedViewTest(LoggedInTestCase): |
| 361 | |
| 362 | |
| 363 | === modified file 'src/maasserver/tests/test_views_settings.py' |
| 364 | === modified file 'src/maasserver/utils/__init__.py' |
| 365 | --- src/maasserver/utils/__init__.py 2012-11-07 19:00:22 +0000 |
| 366 | +++ src/maasserver/utils/__init__.py 2012-11-08 09:19:27 +0000 |
| 367 | @@ -84,6 +84,7 @@ |
| 368 | if query is not None: |
| 369 | url += '?%s' % urlencode(query, doseq=True) |
| 370 | return url |
| 371 | +<<<<<<< TREE |
| 372 | |
| 373 | |
| 374 | def build_absolute_uri(request, path): |
| 375 | @@ -103,3 +104,27 @@ |
| 376 | def strip_domain(hostname): |
| 377 | """Return `hostname` with the domain part removed.""" |
| 378 | return hostname.split('.', 1)[0] |
| 379 | +======= |
| 380 | + |
| 381 | + |
| 382 | +def build_absolute_uri(request, path): |
| 383 | + """Given a full app-relative path, returns an absolute URI. |
| 384 | + |
| 385 | + The path ordinarily starts with a forward-slash... imagine that you've |
| 386 | + magically chroot'ed to your Django application; the path is the absolute |
| 387 | + path to the view within that environment. |
| 388 | + |
| 389 | + The URI returned uses the request to figure out how to make an absolute |
| 390 | + URL. This means that the URI returned will use the same IP address or |
| 391 | + alias that the request came in on. |
| 392 | + """ |
| 393 | + script_name = request.META["SCRIPT_NAME"] |
| 394 | + return "%s://%s%s%s" % ( |
| 395 | + "https" if request.is_secure() else "http", |
| 396 | + request.get_host(), script_name, path) |
| 397 | + |
| 398 | + |
| 399 | +def strip_domain(hostname): |
| 400 | + """Return `hostname` with the domain part removed.""" |
| 401 | + return hostname.split('.', 1)[0] |
| 402 | +>>>>>>> MERGE-SOURCE |
| 403 | |
| 404 | === modified file 'src/maasserver/utils/tests/test_utils.py' |
| 405 | --- src/maasserver/utils/tests/test_utils.py 2012-11-07 19:00:22 +0000 |
| 406 | +++ src/maasserver/utils/tests/test_utils.py 2012-11-08 09:19:27 +0000 |
| 407 | @@ -107,6 +107,7 @@ |
| 408 | NODE_STATUS_CHOICES, but_not=[status]) |
| 409 | node.status = another_status |
| 410 | self.assertEqual(status, get_db_state(node, 'status')) |
| 411 | +<<<<<<< TREE |
| 412 | |
| 413 | |
| 414 | class TestBuildAbsoluteURI(TestCase): |
| 415 | @@ -175,3 +176,80 @@ |
| 416 | inputs = [input for input, _ in input_and_results] |
| 417 | results = [result for _, result in input_and_results] |
| 418 | self.assertEqual(results, map(strip_domain, inputs)) |
| 419 | +======= |
| 420 | + |
| 421 | + |
| 422 | +class TestBuildAbsoluteURI(TestCase): |
| 423 | + """Tests for `build_absolute_uri`.""" |
| 424 | + |
| 425 | + def make_request(self, host="example.com", port=80, script_name="", |
| 426 | + is_secure=False): |
| 427 | + """Return a :class:`HttpRequest` with the given parameters.""" |
| 428 | + request = HttpRequest() |
| 429 | + request.META["SERVER_NAME"] = host |
| 430 | + request.META["SERVER_PORT"] = port |
| 431 | + request.META["SCRIPT_NAME"] = script_name |
| 432 | + request.is_secure = lambda: is_secure |
| 433 | + return request |
| 434 | + |
| 435 | + def test_simple(self): |
| 436 | + request = self.make_request() |
| 437 | + self.assertEqual( |
| 438 | + "http://example.com/fred", |
| 439 | + build_absolute_uri(request, "/fred")) |
| 440 | + |
| 441 | + def test_different_port(self): |
| 442 | + request = self.make_request(port=1234) |
| 443 | + self.assertEqual( |
| 444 | + "http://example.com:1234/fred", |
| 445 | + build_absolute_uri(request, "/fred")) |
| 446 | + |
| 447 | + def test_script_name_is_prefixed(self): |
| 448 | + # The script name is always prefixed to the given path. |
| 449 | + request = self.make_request(script_name="/foo/bar") |
| 450 | + self.assertEqual( |
| 451 | + "http://example.com/foo/bar/fred", |
| 452 | + build_absolute_uri(request, "/fred")) |
| 453 | + |
| 454 | + def test_secure(self): |
| 455 | + request = self.make_request(port=443, is_secure=True) |
| 456 | + self.assertEqual( |
| 457 | + "https://example.com/fred", |
| 458 | + build_absolute_uri(request, "/fred")) |
| 459 | + |
| 460 | + def test_different_port_and_secure(self): |
| 461 | + request = self.make_request(port=9443, is_secure=True) |
| 462 | + self.assertEqual( |
| 463 | + "https://example.com:9443/fred", |
| 464 | + build_absolute_uri(request, "/fred")) |
| 465 | + |
| 466 | + def test_no_leading_forward_slash(self): |
| 467 | + # No attempt is made to ensure that the given path is separated from |
| 468 | + # the to-be-prefixed path. |
| 469 | + request = self.make_request(script_name="/foo") |
| 470 | + self.assertEqual( |
| 471 | + "http://example.com/foobar", |
| 472 | + build_absolute_uri(request, "bar")) |
| 473 | + |
| 474 | + def test_preserve_two_leading_slashes(self): |
| 475 | + # Whilst this shouldn't ordinarily happen, two leading slashes in the |
| 476 | + # path should be preserved, and not treated specially. |
| 477 | + request = self.make_request(script_name="//foo") |
| 478 | + self.assertEqual( |
| 479 | + "http://example.com//foo/fred", |
| 480 | + build_absolute_uri(request, "/fred")) |
| 481 | + |
| 482 | + |
| 483 | +class TestStripDomain(TestCase): |
| 484 | + |
| 485 | + def test_strip_domain(self): |
| 486 | + input_and_results = [ |
| 487 | + ('name.domain', 'name'), |
| 488 | + ('name', 'name'), |
| 489 | + ('name.domain.what', 'name'), |
| 490 | + ('name..domain', 'name'), |
| 491 | + ] |
| 492 | + inputs = [input for input, _ in input_and_results] |
| 493 | + results = [result for _, result in input_and_results] |
| 494 | + self.assertEqual(results, map(strip_domain, inputs)) |
| 495 | +>>>>>>> MERGE-SOURCE |
| 496 | |
| 497 | === modified file 'src/maasserver/views/nodes.py' |
| 498 | === modified file 'src/provisioningserver/boot_images.py' |
| 499 | --- src/provisioningserver/boot_images.py 2012-10-25 07:27:24 +0000 |
| 500 | +++ src/provisioningserver/boot_images.py 2012-11-08 09:19:27 +0000 |
| 501 | @@ -32,10 +32,14 @@ |
| 502 | ) |
| 503 | from provisioningserver.config import Config |
| 504 | from provisioningserver.pxe import tftppath |
| 505 | +<<<<<<< TREE |
| 506 | from provisioningserver.start_cluster_controller import get_cluster_uuid |
| 507 | |
| 508 | |
| 509 | task_logger = get_task_logger(name=__name__) |
| 510 | +======= |
| 511 | +from provisioningserver.start_cluster_controller import get_cluster_uuid |
| 512 | +>>>>>>> MERGE-SOURCE |
| 513 | |
| 514 | |
| 515 | def get_cached_knowledge(): |
| 516 | |
| 517 | === modified file 'src/provisioningserver/dns/config.py' |
| 518 | === modified file 'src/provisioningserver/dns/tests/test_config.py' |
| 519 | === modified file 'src/provisioningserver/tasks.py' |
| 520 | --- src/provisioningserver/tasks.py 2012-11-07 10:39:19 +0000 |
| 521 | +++ src/provisioningserver/tasks.py 2012-11-08 09:19:27 +0000 |
| 522 | @@ -369,6 +369,7 @@ |
| 523 | exc=exc, countdown=UPDATE_NODE_TAGS_RETRY_DELAY) |
| 524 | else: |
| 525 | raise |
| 526 | +<<<<<<< TREE |
| 527 | |
| 528 | |
| 529 | # ===================================================================== |
| 530 | @@ -382,3 +383,18 @@ |
| 531 | env['http_proxy'] = http_proxy |
| 532 | env['https_proxy'] = http_proxy |
| 533 | check_call(['sudo', '-n', 'maas-import-pxe-files'], env=env) |
| 534 | +======= |
| 535 | + |
| 536 | + |
| 537 | +# ===================================================================== |
| 538 | +# Image importing-related tasks |
| 539 | +# ===================================================================== |
| 540 | + |
| 541 | +@task |
| 542 | +def import_pxe_files(http_proxy=None): |
| 543 | + env = dict(os.environ) |
| 544 | + if http_proxy is not None: |
| 545 | + env['http_proxy'] = http_proxy |
| 546 | + env['https_proxy'] = http_proxy |
| 547 | + check_call(['maas-import-pxe-files'], env=env) |
| 548 | +>>>>>>> MERGE-SOURCE |
| 549 | |
| 550 | === modified file 'src/provisioningserver/tests/test_tasks.py' |
| 551 | --- src/provisioningserver/tests/test_tasks.py 2012-11-07 10:39:19 +0000 |
| 552 | +++ src/provisioningserver/tests/test_tasks.py 2012-11-08 09:19:27 +0000 |
| 553 | @@ -64,7 +64,11 @@ |
| 554 | from provisioningserver.tags import MissingCredentials |
| 555 | from provisioningserver.tasks import ( |
| 556 | add_new_dhcp_host_map, |
| 557 | +<<<<<<< TREE |
| 558 | import_boot_images, |
| 559 | +======= |
| 560 | + import_pxe_files, |
| 561 | +>>>>>>> MERGE-SOURCE |
| 562 | Omshell, |
| 563 | power_off, |
| 564 | power_on, |
| 565 | @@ -536,6 +540,7 @@ |
| 566 | self.assertRaises( |
| 567 | MissingCredentials, update_node_tags.delay, tag, |
| 568 | '//node', retry=True) |
| 569 | +<<<<<<< TREE |
| 570 | |
| 571 | |
| 572 | class TestImportPxeFiles(PservTestCase): |
| 573 | @@ -560,3 +565,28 @@ |
| 574 | expected_env = dict(os.environ, http_proxy=proxy, https_proxy=proxy) |
| 575 | recorder.assert_called_once_with( |
| 576 | ['sudo', '-n', 'maas-import-pxe-files'], env=expected_env) |
| 577 | +======= |
| 578 | + |
| 579 | + |
| 580 | +class TestImportPxeFiles(PservTestCase): |
| 581 | + |
| 582 | + def test_import_pxe_files(self): |
| 583 | + recorder = self.patch(tasks, 'check_call', Mock()) |
| 584 | + import_pxe_files() |
| 585 | + recorder.assert_called_once_with(['maas-import-pxe-files'], env=ANY) |
| 586 | + self.assertIsInstance(import_pxe_files, Task) |
| 587 | + |
| 588 | + def test_import_pxe_files_preserves_environment(self): |
| 589 | + recorder = self.patch(tasks, 'check_call', Mock()) |
| 590 | + import_pxe_files() |
| 591 | + recorder.assert_called_once_with( |
| 592 | + ['maas-import-pxe-files'], env=os.environ) |
| 593 | + |
| 594 | + def test_import_pxe_files_sets_proxy(self): |
| 595 | + recorder = self.patch(tasks, 'check_call', Mock()) |
| 596 | + proxy = factory.getRandomString() |
| 597 | + import_pxe_files(http_proxy=proxy) |
| 598 | + expected_env = dict(os.environ, http_proxy=proxy, https_proxy=proxy) |
| 599 | + recorder.assert_called_once_with( |
| 600 | + ['maas-import-pxe-files'], env=expected_env) |
| 601 | +>>>>>>> MERGE-SOURCE |

