Merge lp:~jtv/maas/bug-1372735 into lp:~maas-committers/maas/trunk

Proposed by Jeroen T. Vermeulen
Status: Rejected
Rejected by: Jeroen T. Vermeulen
Proposed branch: lp:~jtv/maas/bug-1372735
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~jtv/maas/bug-1372732
Diff against target: 567 lines (+88/-75)
15 files modified
src/maasserver/api/commissioning_scripts.py (+3/-3)
src/maasserver/api/tests/test_nodegroup.py (+3/-3)
src/maasserver/forms.py (+2/-2)
src/maasserver/models/filestorage.py (+3/-3)
src/maasserver/models/tests/test_node.py (+3/-3)
src/maasserver/testing/factory.py (+4/-4)
src/maasserver/tests/test_third_party_drivers.py (+2/-2)
src/metadataserver/api.py (+4/-3)
src/metadataserver/fields.py (+25/-16)
src/metadataserver/migrations/0012_commission_result_binary_data_recode.py (+2/-3)
src/metadataserver/models/commissioningscript.py (+3/-3)
src/metadataserver/models/nodeuserdata.py (+4/-4)
src/metadataserver/models/tests/test_nodecommissionresult.py (+3/-3)
src/metadataserver/models/tests/test_noderesults.py (+2/-2)
src/metadataserver/tests/test_fields.py (+25/-21)
To merge this branch: bzr merge lp:~jtv/maas/bug-1372735
Reviewer Review Type Date Requested Status
Gavin Panella (community) Needs Information
Review via email: mp+235559@code.launchpad.net

This proposal supersedes a proposal from 2014-09-23.

Commit message

Fix DeprecationWarning in Bin class. It was showing up in Twisted logs, which in turn broke Node model tests sometimes (because they checked for the log to be empty).

The warning was about object.__init__ not wanting to receive arguments during the super() upcall from Bin.__init__. Even making just a direct upcall to bytes.__init__ (because Bin is derived from bytes, not from object directly) did not fix it. And so I had to replace use of the Bin constructor with a little factory.

Description of the change

I did want to keep the safety of checking against the wrong values being passed in, especially unicode or None. I don't see any way to check that _after_ construction, and I couldn't write my own constructor, so I had to get in _before_ construction.

Most of the diff will be pointless context around tiny mechanical changes in usage. It's actually quite a small change.

Jeroen

To post a comment you must log in.
Revision history for this message
Newell Jensen (newell-jensen) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Gavin Panella (allenap) wrote :

I think there's a much simpler fix, but have a look and check that it does what you need.

review: Needs Information
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Proposing your version as a fresh branch.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/api/commissioning_scripts.py'
--- src/maasserver/api/commissioning_scripts.py 2014-08-17 01:33:52 +0000
+++ src/maasserver/api/commissioning_scripts.py 2014-09-23 04:43:27 +0000
@@ -21,7 +21,7 @@
21from django.shortcuts import get_object_or_40421from django.shortcuts import get_object_or_404
22from maasserver.api.support import OperationsHandler22from maasserver.api.support import OperationsHandler
23from maasserver.api.utils import get_mandatory_param23from maasserver.api.utils import get_mandatory_param
24from metadataserver.fields import Bin24from metadataserver.fields import wrap_bin
25from metadataserver.models import CommissioningScript25from metadataserver.models import CommissioningScript
26from piston.utils import rc26from piston.utils import rc
2727
@@ -80,7 +80,7 @@
80 is ignored; MAAS will know it by the name you pass to the request.80 is ignored; MAAS will know it by the name you pass to the request.
81 """81 """
82 name = get_mandatory_param(request.data, 'name')82 name = get_mandatory_param(request.data, 'name')
83 content = Bin(get_content_parameter(request))83 content = wrap_bin(get_content_parameter(request))
84 return CommissioningScript.objects.create(name=name, content=content)84 return CommissioningScript.objects.create(name=name, content=content)
8585
86 @classmethod86 @classmethod
@@ -114,7 +114,7 @@
114114
115 def update(self, request, name):115 def update(self, request, name):
116 """Update a commissioning script."""116 """Update a commissioning script."""
117 content = Bin(get_content_parameter(request))117 content = wrap_bin(get_content_parameter(request))
118 script = get_object_or_404(CommissioningScript, name=name)118 script = get_object_or_404(CommissioningScript, name=name)
119 script.content = content119 script.content = content
120 script.save()120 script.save()
121121
=== modified file 'src/maasserver/api/tests/test_nodegroup.py'
--- src/maasserver/api/tests/test_nodegroup.py 2014-09-15 14:28:28 +0000
+++ src/maasserver/api/tests/test_nodegroup.py 2014-09-23 04:43:27 +0000
@@ -48,7 +48,7 @@
48from maastesting.celery import CeleryFixture48from maastesting.celery import CeleryFixture
49from maastesting.matchers import MockCalledOnceWith49from maastesting.matchers import MockCalledOnceWith
50from metadataserver.enum import RESULT_TYPE50from metadataserver.enum import RESULT_TYPE
51from metadataserver.fields import Bin51from metadataserver.fields import wrap_bin
52from metadataserver.models import (52from metadataserver.models import (
53 commissioningscript,53 commissioningscript,
54 NodeResult,54 NodeResult,
@@ -416,7 +416,7 @@
416 NodeResult.objects.store_data(416 NodeResult.objects.store_data(
417 node, commissioningscript.LSHW_OUTPUT_NAME,417 node, commissioningscript.LSHW_OUTPUT_NAME,
418 script_result=0, result_type=RESULT_TYPE.COMMISSIONING,418 script_result=0, result_type=RESULT_TYPE.COMMISSIONING,
419 data=Bin(data))419 data=wrap_bin(data))
420420
421 example_lldp_details = dedent("""\421 example_lldp_details = dedent("""\
422 <?xml version="1.0" encoding="UTF-8"?>422 <?xml version="1.0" encoding="UTF-8"?>
@@ -429,7 +429,7 @@
429 NodeResult.objects.store_data(429 NodeResult.objects.store_data(
430 node, commissioningscript.LLDP_OUTPUT_NAME,430 node, commissioningscript.LLDP_OUTPUT_NAME,
431 script_result=0, result_type=RESULT_TYPE.COMMISSIONING,431 script_result=0, result_type=RESULT_TYPE.COMMISSIONING,
432 data=Bin(data))432 data=wrap_bin(data))
433433
434 def test_nodegroup_requires_authentication(self):434 def test_nodegroup_requires_authentication(self):
435 nodegroup = factory.make_NodeGroup()435 nodegroup = factory.make_NodeGroup()
436436
=== modified file 'src/maasserver/forms.py'
--- src/maasserver/forms.py 2014-09-22 05:36:10 +0000
+++ src/maasserver/forms.py 2014-09-23 04:43:27 +0000
@@ -142,7 +142,7 @@
142 list_osystem_choices,142 list_osystem_choices,
143 list_release_choices,143 list_release_choices,
144 )144 )
145from metadataserver.fields import Bin145from metadataserver.fields import wrap_bin
146from metadataserver.models import CommissioningScript146from metadataserver.models import CommissioningScript
147from netaddr import IPAddress147from netaddr import IPAddress
148from provisioningserver.drivers.osystem import OperatingSystemRegistry148from provisioningserver.drivers.osystem import OperatingSystemRegistry
@@ -1620,7 +1620,7 @@
1620 content = self.cleaned_data['content']1620 content = self.cleaned_data['content']
1621 CommissioningScript.objects.create(1621 CommissioningScript.objects.create(
1622 name=content.name,1622 name=content.name,
1623 content=Bin(content.read()))1623 content=wrap_bin(content.read()))
16241624
16251625
1626class UnconstrainedMultipleChoiceField(MultipleChoiceField):1626class UnconstrainedMultipleChoiceField(MultipleChoiceField):
16271627
=== modified file 'src/maasserver/models/filestorage.py'
--- src/maasserver/models/filestorage.py 2013-10-07 09:12:40 +0000
+++ src/maasserver/models/filestorage.py 2014-09-23 04:43:27 +0000
@@ -1,4 +1,4 @@
1# Copyright 2012 Canonical Ltd. This software is licensed under the1# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Storage for uploaded files."""4"""Storage for uploaded files."""
@@ -31,8 +31,8 @@
31from maasserver import DefaultMeta31from maasserver import DefaultMeta
32from maasserver.models.cleansave import CleanSave32from maasserver.models.cleansave import CleanSave
33from metadataserver.fields import (33from metadataserver.fields import (
34 Bin,
35 BinaryField,34 BinaryField,
35 wrap_bin,
36 )36 )
3737
3838
@@ -59,7 +59,7 @@
59 """59 """
60 # This probably ought to read in chunks but large files are60 # This probably ought to read in chunks but large files are
61 # not expected.61 # not expected.
62 content = Bin(file_object.read())62 content = wrap_bin(file_object.read())
63 storage, created = self.get_or_create(63 storage, created = self.get_or_create(
64 filename=filename, owner=owner, defaults={'content': content})64 filename=filename, owner=owner, defaults={'content': content})
65 if not created:65 if not created:
6666
=== modified file 'src/maasserver/models/tests/test_node.py'
--- src/maasserver/models/tests/test_node.py 2014-09-22 06:29:06 +0000
+++ src/maasserver/models/tests/test_node.py 2014-09-23 04:43:27 +0000
@@ -78,7 +78,7 @@
78from maastesting.testcase import MAASTestCase78from maastesting.testcase import MAASTestCase
79from metadataserver import commissioning79from metadataserver import commissioning
80from metadataserver.enum import RESULT_TYPE80from metadataserver.enum import RESULT_TYPE
81from metadataserver.fields import Bin81from metadataserver.fields import wrap_bin
82from metadataserver.models import (82from metadataserver.models import (
83 NodeResult,83 NodeResult,
84 NodeUserData,84 NodeUserData,
@@ -1050,7 +1050,7 @@
1050 node, factory.make_string(),1050 node, factory.make_string(),
1051 random.randint(0, 10),1051 random.randint(0, 10),
1052 RESULT_TYPE.COMMISSIONING,1052 RESULT_TYPE.COMMISSIONING,
1053 Bin(factory.make_bytes()))1053 wrap_bin(factory.make_bytes()))
1054 node.start_commissioning(factory.make_admin())1054 node.start_commissioning(factory.make_admin())
1055 self.assertItemsEqual([], node.noderesult_set.all())1055 self.assertItemsEqual([], node.noderesult_set.all())
10561056
@@ -1061,7 +1061,7 @@
1061 script_result = random.randint(0, 10)1061 script_result = random.randint(0, 10)
1062 NodeResult.objects.store_data(1062 NodeResult.objects.store_data(
1063 node, filename, script_result, RESULT_TYPE.COMMISSIONING,1063 node, filename, script_result, RESULT_TYPE.COMMISSIONING,
1064 Bin(data))1064 wrap_bin(data))
1065 other_node = factory.make_Node(status=NODE_STATUS.NEW)1065 other_node = factory.make_Node(status=NODE_STATUS.NEW)
1066 other_node.start_commissioning(factory.make_admin())1066 other_node.start_commissioning(factory.make_admin())
1067 self.assertEqual(1067 self.assertEqual(
10681068
=== modified file 'src/maasserver/testing/factory.py'
--- src/maasserver/testing/factory.py 2014-09-19 12:48:48 +0000
+++ src/maasserver/testing/factory.py 2014-09-23 04:43:27 +0000
@@ -76,7 +76,7 @@
76import maastesting.factory76import maastesting.factory
77from maastesting.factory import NO_VALUE77from maastesting.factory import NO_VALUE
78from metadataserver.enum import RESULT_TYPE78from metadataserver.enum import RESULT_TYPE
79from metadataserver.fields import Bin79from metadataserver.fields import wrap_bin
80from metadataserver.models import (80from metadataserver.models import (
81 CommissioningScript,81 CommissioningScript,
82 NodeResult,82 NodeResult,
@@ -445,7 +445,7 @@
445 script_result = random.randint(0, 10)445 script_result = random.randint(0, 10)
446 ncr = NodeResult(446 ncr = NodeResult(
447 node=node, name=name, script_result=script_result,447 node=node, name=name, script_result=script_result,
448 result_type=RESULT_TYPE.COMMISSIONING, data=Bin(data))448 result_type=RESULT_TYPE.COMMISSIONING, data=wrap_bin(data))
449 ncr.save()449 ncr.save()
450 return ncr450 return ncr
451451
@@ -462,7 +462,7 @@
462 script_result = random.randint(0, 10)462 script_result = random.randint(0, 10)
463 ncr = NodeResult(463 ncr = NodeResult(
464 node=node, name=name, script_result=script_result,464 node=node, name=name, script_result=script_result,
465 result_type=RESULT_TYPE.INSTALLING, data=Bin(data))465 result_type=RESULT_TYPE.INSTALLING, data=wrap_bin(data))
466 ncr.save()466 ncr.save()
467 return ncr467 return ncr
468468
@@ -707,7 +707,7 @@
707 if content is None:707 if content is None:
708 content = b'content:' + self.make_string().encode('ascii')708 content = b'content:' + self.make_string().encode('ascii')
709 return CommissioningScript.objects.create(709 return CommissioningScript.objects.create(
710 name=name, content=Bin(content))710 name=name, content=wrap_bin(content))
711711
712 def make_DownloadProgress(self, nodegroup=None, filename=None,712 def make_DownloadProgress(self, nodegroup=None, filename=None,
713 size=NO_VALUE, bytes_downloaded=NO_VALUE,713 size=NO_VALUE, bytes_downloaded=NO_VALUE,
714714
=== modified file 'src/maasserver/tests/test_third_party_drivers.py'
--- src/maasserver/tests/test_third_party_drivers.py 2014-09-10 16:20:31 +0000
+++ src/maasserver/tests/test_third_party_drivers.py 2014-09-23 04:43:27 +0000
@@ -28,7 +28,7 @@
28from maastesting import root28from maastesting import root
29from maastesting.testcase import MAASTestCase29from maastesting.testcase import MAASTestCase
30from metadataserver.enum import RESULT_TYPE30from metadataserver.enum import RESULT_TYPE
31from metadataserver.fields import Bin31from metadataserver.fields import wrap_bin
32from metadataserver.models import (32from metadataserver.models import (
33 commissioningscript,33 commissioningscript,
34 NodeResult,34 NodeResult,
@@ -42,7 +42,7 @@
42 node = factory.make_Node()42 node = factory.make_Node()
43 NodeResult.objects.store_data(43 NodeResult.objects.store_data(
44 node, commissioningscript.LIST_MODALIASES_OUTPUT_NAME,44 node, commissioningscript.LIST_MODALIASES_OUTPUT_NAME,
45 0, RESULT_TYPE.COMMISSIONING, Bin(test_data))45 0, RESULT_TYPE.COMMISSIONING, wrap_bin(test_data))
4646
47 aliases = node_modaliases(node)47 aliases = node_modaliases(node)
48 self.assertEqual(['hulla', 'baloo'], aliases)48 self.assertEqual(['hulla', 'baloo'], aliases)
4949
=== modified file 'src/metadataserver/api.py'
--- src/metadataserver/api.py 2014-08-22 16:25:29 +0000
+++ src/metadataserver/api.py 2014-09-23 04:43:27 +0000
@@ -67,7 +67,7 @@
67 RESULT_TYPE,67 RESULT_TYPE,
68 SIGNAL_STATUS,68 SIGNAL_STATUS,
69 )69 )
70from metadataserver.fields import Bin70from metadataserver.fields import wrap_bin
71from metadataserver.models import (71from metadataserver.models import (
72 CommissioningScript,72 CommissioningScript,
73 NodeKey,73 NodeKey,
@@ -210,7 +210,7 @@
210 raw_content = uploaded_file.read()210 raw_content = uploaded_file.read()
211 NodeResult.objects.store_data(211 NodeResult.objects.store_data(
212 node, name, script_result=0,212 node, name, script_result=0,
213 result_type=RESULT_TYPE.INSTALLING, data=Bin(raw_content))213 result_type=RESULT_TYPE.INSTALLING, data=wrap_bin(raw_content))
214214
215 def _store_commissioning_results(self, node, request):215 def _store_commissioning_results(self, node, request):
216 """Store commissioning result files for `node`."""216 """Store commissioning result files for `node`."""
@@ -224,7 +224,8 @@
224 exit_status=script_result)224 exit_status=script_result)
225 NodeResult.objects.store_data(225 NodeResult.objects.store_data(
226 node, name, script_result,226 node, name, script_result,
227 result_type=RESULT_TYPE.COMMISSIONING, data=Bin(raw_content))227 result_type=RESULT_TYPE.COMMISSIONING,
228 data=wrap_bin(raw_content))
228229
229 @operation(idempotent=False)230 @operation(idempotent=False)
230 def signal(self, request, version=None, mac=None):231 def signal(self, request, version=None, mac=None):
231232
=== modified file 'src/metadataserver/fields.py'
--- src/metadataserver/fields.py 2013-10-21 05:31:09 +0000
+++ src/metadataserver/fields.py 2014-09-23 04:43:27 +0000
@@ -1,4 +1,4 @@
1# Copyright 2012 Canonical Ltd. This software is licensed under the1# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Custom field types for the metadata server."""4"""Custom field types for the metadata server."""
@@ -14,6 +14,7 @@
14__metaclass__ = type14__metaclass__ = type
15__all__ = [15__all__ = [
16 'BinaryField',16 'BinaryField',
17 'wrap_bin',
17 ]18 ]
1819
19from base64 import (20from base64 import (
@@ -29,6 +30,26 @@
29from south.modelsinspector import add_introspection_rules30from south.modelsinspector import add_introspection_rules
3031
3132
33def wrap_bin(binary_data):
34 """Wrap a `bytes` into a `Bin`.
35
36 Use this to construct a `Bin`, a marker class with which we wrap binary
37 data. Otherwise Django field conversions won't be able to tell a binary
38 value as found in the database from one that's already been "converted" to
39 a Python object.
40
41 :param binary_data: A `bytes` object. Nothing else is accepted.
42 :return: A `Bin` containing `binary_data`.
43 """
44 # We can't give `Bin` its own constructor to check this, because the
45 # upcall to bytes.__init__ triggers a DeprecationWarning about
46 # object.__init__ no longer accepting arguments. (This happens even with
47 # a direct upcall; it's not just super() that causes it.)
48 assert isinstance(binary_data, bytes), (
49 "Not a binary string: '%s'." % repr(binary_data))
50 return Bin(binary_data)
51
52
32class Bin(bytes):53class Bin(bytes):
33 """Wrapper class to convince django that a string is really binary.54 """Wrapper class to convince django that a string is really binary.
3455
@@ -39,24 +60,12 @@
39 can stay as it is). The line between bytes and unicode is dangerously60 can stay as it is). The line between bytes and unicode is dangerously
40 thin.61 thin.
4162
42 So, to store a value in a BinaryField, wrap it in a Bin:63 So, to store a value in a BinaryField, wrap it in a Bin. Use the
64 `wrap_bin` factory:
4365
44 my_model_object.binary_data = Bin(b"\x01\x02\x03")66 my_model_object.binary_data = wrap_bin(b"\x01\x02\x03")
45 """67 """
4668
47 def __init__(self, initializer):
48 """Wrap a bytes.
49
50 :param initializer: Binary string of data for this Bin. This must
51 be a bytes. Anything else is almost certainly a mistake, so e.g.
52 this constructor will refuse to render None as b'None'.
53 :type initializer: bytes
54 """
55 if not isinstance(initializer, bytes):
56 raise AssertionError(
57 "Not a binary string: '%s'" % repr(initializer))
58 super(Bin, self).__init__(initializer)
59
60 def __emittable__(self):69 def __emittable__(self):
61 """Emit base-64 encoded bytes.70 """Emit base-64 encoded bytes.
6271
6372
=== modified file 'src/metadataserver/migrations/0012_commission_result_binary_data_recode.py'
--- src/metadataserver/migrations/0012_commission_result_binary_data_recode.py 2014-03-27 04:15:45 +0000
+++ src/metadataserver/migrations/0012_commission_result_binary_data_recode.py 2014-09-23 04:43:27 +0000
@@ -1,7 +1,6 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2import datetime2import datetime
33
4from django.db import models
5from south.db import db4from south.db import db
6from south.v2 import DataMigration5from south.v2 import DataMigration
76
@@ -10,9 +9,9 @@
109
11 def forwards(self, orm):10 def forwards(self, orm):
12 "Write your forwards methods here."11 "Write your forwards methods here."
13 from metadataserver.fields import Bin12 from metadataserver.fields import wrap_bin
14 for result in orm.NodeCommissionResult.objects.all():13 for result in orm.NodeCommissionResult.objects.all():
15 result.data_bin = Bin(result.data.encode("utf-8"))14 result.data_bin = wrap_bin(result.data.encode("utf-8"))
16 result.save()15 result.save()
1716
18 def backwards(self, orm):17 def backwards(self, orm):
1918
=== modified file 'src/metadataserver/models/commissioningscript.py'
--- src/metadataserver/models/commissioningscript.py 2014-08-13 21:49:35 +0000
+++ src/metadataserver/models/commissioningscript.py 2014-09-23 04:43:27 +0000
@@ -1,4 +1,4 @@
1# Copyright 2012, 2013 Canonical Ltd. This software is licensed under the1# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Custom commissioning scripts, and their database backing."""4"""Custom commissioning scripts, and their database backing."""
@@ -47,8 +47,8 @@
47from metadataserver import DefaultMeta47from metadataserver import DefaultMeta
48from metadataserver.enum import RESULT_TYPE48from metadataserver.enum import RESULT_TYPE
49from metadataserver.fields import (49from metadataserver.fields import (
50 Bin,
51 BinaryField,50 BinaryField,
51 wrap_bin,
52 )52 )
53from metadataserver.models.noderesult import NodeResult53from metadataserver.models.noderesult import NodeResult
5454
@@ -467,7 +467,7 @@
467 assert isinstance(output, bytes)467 assert isinstance(output, bytes)
468 NodeResult.objects.store_data(468 NodeResult.objects.store_data(
469 node, name, script_result=exit_status,469 node, name, script_result=exit_status,
470 result_type=RESULT_TYPE.COMMISSIONING, data=Bin(output))470 result_type=RESULT_TYPE.COMMISSIONING, data=wrap_bin(output))
471 if name in BUILTIN_COMMISSIONING_SCRIPTS:471 if name in BUILTIN_COMMISSIONING_SCRIPTS:
472 postprocess_hook = BUILTIN_COMMISSIONING_SCRIPTS[name]['hook']472 postprocess_hook = BUILTIN_COMMISSIONING_SCRIPTS[name]['hook']
473 postprocess_hook(node=node, output=output, exit_status=exit_status)473 postprocess_hook(node=node, output=output, exit_status=exit_status)
474474
=== modified file 'src/metadataserver/models/nodeuserdata.py'
--- src/metadataserver/models/nodeuserdata.py 2014-09-02 12:34:10 +0000
+++ src/metadataserver/models/nodeuserdata.py 2014-09-23 04:43:27 +0000
@@ -1,4 +1,4 @@
1# Copyright 2012 Canonical Ltd. This software is licensed under the1# Copyright 2012-2014 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Node user-data for cloud-init's use."""4"""Node user-data for cloud-init's use."""
@@ -25,8 +25,8 @@
25from maasserver.models.cleansave import CleanSave25from maasserver.models.cleansave import CleanSave
26from metadataserver import DefaultMeta26from metadataserver import DefaultMeta
27from metadataserver.fields import (27from metadataserver.fields import (
28 Bin,
29 BinaryField,28 BinaryField,
29 wrap_bin,
30 )30 )
3131
3232
@@ -53,7 +53,7 @@
5353
54 def _set(self, node, data):54 def _set(self, node, data):
55 """Set actual user data for a node. Not usable if data is None."""55 """Set actual user data for a node. Not usable if data is None."""
56 wrapped_data = Bin(data)56 wrapped_data = wrap_bin(data)
57 (existing_entry, created) = self.get_or_create(57 (existing_entry, created) = self.get_or_create(
58 node=node, defaults={'data': wrapped_data})58 node=node, defaults={'data': wrapped_data})
59 if not created:59 if not created:
@@ -72,7 +72,7 @@
72 self.filter(node__in=nodes).delete()72 self.filter(node__in=nodes).delete()
73 if data is not None:73 if data is not None:
74 self.bulk_create((74 self.bulk_create((
75 self.model(node=node, data=Bin(data))75 self.model(node=node, data=wrap_bin(data))
76 for node in nodes76 for node in nodes
77 ))77 ))
7878
7979
=== modified file 'src/metadataserver/models/tests/test_nodecommissionresult.py'
--- src/metadataserver/models/tests/test_nodecommissionresult.py 2014-09-15 14:28:28 +0000
+++ src/metadataserver/models/tests/test_nodecommissionresult.py 2014-09-23 04:43:27 +0000
@@ -22,7 +22,7 @@
22from maasserver.utils.converters import XMLToYAML22from maasserver.utils.converters import XMLToYAML
23from maastesting.djangotestcase import DjangoTestCase23from maastesting.djangotestcase import DjangoTestCase
24from metadataserver.enum import RESULT_TYPE24from metadataserver.enum import RESULT_TYPE
25from metadataserver.fields import Bin25from metadataserver.fields import wrap_bin
26from metadataserver.models import NodeResult26from metadataserver.models import NodeResult
27from metadataserver.models.commissioningscript import (27from metadataserver.models.commissioningscript import (
28 LLDP_OUTPUT_NAME,28 LLDP_OUTPUT_NAME,
@@ -133,7 +133,7 @@
133 script_result = randint(0, 10)133 script_result = randint(0, 10)
134 result = NodeResult.objects.store_data(134 result = NodeResult.objects.store_data(
135 node, name=name, script_result=script_result,135 node, name=name, script_result=script_result,
136 result_type=RESULT_TYPE.COMMISSIONING, data=Bin(data))136 result_type=RESULT_TYPE.COMMISSIONING, data=wrap_bin(data))
137 result_in_db = NodeResult.objects.get(node=node)137 result_in_db = NodeResult.objects.get(node=node)
138138
139 self.assertAttributes(result_in_db, dict(name=name, data=data))139 self.assertAttributes(result_in_db, dict(name=name, data=data))
@@ -148,7 +148,7 @@
148 data = factory.make_bytes(1024 * 1024)148 data = factory.make_bytes(1024 * 1024)
149 NodeResult.objects.store_data(149 NodeResult.objects.store_data(
150 node, name=name, script_result=script_result,150 node, name=name, script_result=script_result,
151 result_type=RESULT_TYPE.COMMISSIONING, data=Bin(data))151 result_type=RESULT_TYPE.COMMISSIONING, data=wrap_bin(data))
152152
153 self.assertAttributes(153 self.assertAttributes(
154 NodeResult.objects.get(node=node),154 NodeResult.objects.get(node=node),
155155
=== modified file 'src/metadataserver/models/tests/test_noderesults.py'
--- src/metadataserver/models/tests/test_noderesults.py 2014-09-10 16:20:31 +0000
+++ src/metadataserver/models/tests/test_noderesults.py 2014-09-23 04:43:27 +0000
@@ -45,7 +45,7 @@
45from maastesting.matchers import MockCalledOnceWith45from maastesting.matchers import MockCalledOnceWith
46from maastesting.utils import sample_binary_data46from maastesting.utils import sample_binary_data
47from metadataserver.enum import RESULT_TYPE47from metadataserver.enum import RESULT_TYPE
48from metadataserver.fields import Bin48from metadataserver.fields import wrap_bin
49from metadataserver.models import (49from metadataserver.models import (
50 CommissioningScript,50 CommissioningScript,
51 commissioningscript as cs_module,51 commissioningscript as cs_module,
@@ -153,7 +153,7 @@
153 def test_scripts_may_be_binary(self):153 def test_scripts_may_be_binary(self):
154 name = make_script_name()154 name = make_script_name()
155 CommissioningScript.objects.create(155 CommissioningScript.objects.create(
156 name=name, content=Bin(sample_binary_data))156 name=name, content=wrap_bin(sample_binary_data))
157 stored_script = CommissioningScript.objects.get(name=name)157 stored_script = CommissioningScript.objects.get(name=name)
158 self.assertEqual(sample_binary_data, stored_script.content)158 self.assertEqual(sample_binary_data, stored_script.content)
159159
160160
=== modified file 'src/metadataserver/tests/test_fields.py'
--- src/metadataserver/tests/test_fields.py 2014-07-18 17:05:57 +0000
+++ src/metadataserver/tests/test_fields.py 2014-09-23 04:43:27 +0000
@@ -22,6 +22,7 @@
22from metadataserver.fields import (22from metadataserver.fields import (
23 Bin,23 Bin,
24 BinaryField,24 BinaryField,
25 wrap_bin,
25 )26 )
26from metadataserver.tests.models import BinaryFieldModel27from metadataserver.tests.models import BinaryFieldModel
2728
@@ -29,24 +30,27 @@
29class TestBin(MAASServerTestCase):30class TestBin(MAASServerTestCase):
30 """Test Bin helper class."""31 """Test Bin helper class."""
3132
32 def test_is_basically_bytes(self):33 def test__is_what_wrap_bin_returns(self):
33 self.assertEqual(b"Hello", Bin(b"Hello"))34 self.assertIsInstance(wrap_bin(b"Hi"), Bin)
3435
35 def test_refuses_to_construct_from_unicode(self):36 def test__is_basically_bytes(self):
36 self.assertRaises(AssertionError, Bin, "Hello")37 self.assertEqual(b"Hello", wrap_bin(b"Hello"))
3738
38 def test_refuses_to_construct_from_None(self):39 def test__refuses_to_construct_from_unicode(self):
39 self.assertRaises(AssertionError, Bin, None)40 self.assertRaises(AssertionError, wrap_bin, "Hello")
4041
41 def test_emits_base64(self):42 def test__refuses_to_construct_from_None(self):
43 self.assertRaises(AssertionError, wrap_bin, None)
44
45 def test__emits_base64(self):
42 # Piston hooks onto an __emittable__() method, if present.46 # Piston hooks onto an __emittable__() method, if present.
43 # Bin() returns a base-64 encoded string so that it can be47 # Bin() returns a base-64 encoded string so that it can be
44 # transmitted in JSON.48 # transmitted in JSON.
45 self.assertEqual(b"", Bin(b"").__emittable__())49 self.assertEqual(b"", wrap_bin(b"").__emittable__())
46 example_bytes = factory.make_bytes()50 example_bytes = factory.make_bytes()
47 self.assertEqual(51 self.assertEqual(
48 b64encode(example_bytes),52 b64encode(example_bytes),
49 Bin(example_bytes).__emittable__())53 wrap_bin(example_bytes).__emittable__())
5054
5155
52class TestBinaryField(TestModelMixin, MAASServerTestCase):56class TestBinaryField(TestModelMixin, MAASServerTestCase):
@@ -62,7 +66,7 @@
62 BinaryFieldModel.objects.get(id=binary_item.id).data)66 BinaryFieldModel.objects.get(id=binary_item.id).data)
6367
64 def test_stores_and_retrieves_empty_data(self):68 def test_stores_and_retrieves_empty_data(self):
65 binary_item = BinaryFieldModel(data=Bin(b''))69 binary_item = BinaryFieldModel(data=wrap_bin(b''))
66 self.assertEqual(b'', binary_item.data)70 self.assertEqual(b'', binary_item.data)
67 binary_item.save()71 binary_item.save()
68 self.assertEqual(72 self.assertEqual(
@@ -70,7 +74,7 @@
7074
71 def test_does_not_truncate_at_zero_bytes(self):75 def test_does_not_truncate_at_zero_bytes(self):
72 data = b"BEFORE THE ZERO\x00AFTER THE ZERO"76 data = b"BEFORE THE ZERO\x00AFTER THE ZERO"
73 binary_item = BinaryFieldModel(data=Bin(data))77 binary_item = BinaryFieldModel(data=wrap_bin(data))
74 self.assertEqual(data, binary_item.data)78 self.assertEqual(data, binary_item.data)
75 binary_item.save()79 binary_item.save()
76 self.assertEqual(80 self.assertEqual(
@@ -78,24 +82,24 @@
7882
79 def test_stores_and_retrieves_binary_data(self):83 def test_stores_and_retrieves_binary_data(self):
80 data = b"\x01\x02\xff\xff\xfe\xff\xff\xfe"84 data = b"\x01\x02\xff\xff\xfe\xff\xff\xfe"
81 binary_item = BinaryFieldModel(data=Bin(data))85 binary_item = BinaryFieldModel(data=wrap_bin(data))
82 self.assertEqual(data, binary_item.data)86 self.assertEqual(data, binary_item.data)
83 binary_item.save()87 binary_item.save()
84 self.assertEqual(88 self.assertEqual(
85 data, BinaryFieldModel.objects.get(id=binary_item.id).data)89 data, BinaryFieldModel.objects.get(id=binary_item.id).data)
8690
87 def test_returns_bytes_not_text(self):91 def test_returns_bytes_not_text(self):
88 binary_item = BinaryFieldModel(data=Bin(b"Data"))92 binary_item = BinaryFieldModel(data=wrap_bin(b"Data"))
89 binary_item.save()93 binary_item.save()
90 retrieved_data = BinaryFieldModel.objects.get(id=binary_item.id).data94 retrieved_data = BinaryFieldModel.objects.get(id=binary_item.id).data
91 self.assertIsInstance(retrieved_data, bytes)95 self.assertIsInstance(retrieved_data, bytes)
9296
93 def test_looks_up_data(self):97 def test_looks_up_data(self):
94 data = b"Binary item"98 data = b"Binary item"
95 binary_item = BinaryFieldModel(data=Bin(data))99 binary_item = BinaryFieldModel(data=wrap_bin(data))
96 binary_item.save()100 binary_item.save()
97 self.assertEqual(101 self.assertEqual(
98 binary_item, BinaryFieldModel.objects.get(data=Bin(data)))102 binary_item, BinaryFieldModel.objects.get(data=wrap_bin(data)))
99103
100 def test_get_default_returns_None(self):104 def test_get_default_returns_None(self):
101 field = BinaryField(null=True)105 field = BinaryField(null=True)
@@ -104,10 +108,10 @@
104108
105 def test_get_default_returns_Bin(self):109 def test_get_default_returns_Bin(self):
106 field = BinaryField(null=True)110 field = BinaryField(null=True)
107 self.patch(field, "default", Bin(b"wotcha"))111 self.patch(field, "default", wrap_bin(b"wotcha"))
108 self.assertEqual(Bin(b"wotcha"), field.get_default())112 self.assertEqual(wrap_bin(b"wotcha"), field.get_default())
109113
110 def test_get_default_returns_Bin_from_bytes(self):114 def test_get_default_returns_Bin_from_bytes(self):
111 field = BinaryField(null=True)115 field = BinaryField(null=True)
112 self.patch(field, "default", b"wotcha")116 self.patch(field, "default", b"wotcha")
113 self.assertEqual(Bin(b"wotcha"), field.get_default())117 self.assertEqual(wrap_bin(b"wotcha"), field.get_default())