Merge ~chad.smith/cloud-init:bug/1776701-openstack-local-no-probe-on-ec2 into cloud-init:master

Proposed by Chad Smith
Status: Merged
Approved by: Chad Smith
Approved revision: 69b62008c859790f94dddd93f8bd704edd8bd0c6
Merge reported by: Chad Smith
Merged at revision: 1efa8a0a030794cec68197100f31a856d0d264ab
Proposed branch: ~chad.smith/cloud-init:bug/1776701-openstack-local-no-probe-on-ec2
Merge into: cloud-init:master
Diff against target: 333 lines (+182/-16)
5 files modified
cloudinit/sources/DataSourceOpenStack.py (+23/-0)
cloudinit/util.py (+11/-2)
doc/rtd/topics/datasources/openstack.rst (+15/-0)
tests/unittests/test_datasource/test_openstack.py (+110/-14)
tests/unittests/test_util.py (+23/-0)
Reviewer Review Type Date Requested Status
Chad Smith Abstain
Scott Moser Approve
Server Team CI bot continuous-integration Approve
Review via email: mp+347937@code.launchpad.net

Commit message

openstack: avoid unneeded metadata probe on non-openstack platforms

OpenStack datasource is now discovered in init-local stage. In order to
probe whether OpenStack metadata is present, it performs a costly
sandboxed dhclient setup and metadata probe against http://169.254.169.254
for openstack data.

Cloud-init properly detects non-OpenStack on EC2, but it spends precious
time probing the metadata service also resulting in a confusing WARNING
log about 'metadata not present'. To avoid the wasted cycles, and
confusing warning, get_data will call a detect_openstack function to
quickly determine whether the platform looks like OpenStack before trying
to setup network to probe and crawl the metadata service.

LP: #1776701

Description of the change

detect_openstack function is basically logic adapted from ./tools/ds-identify for detecting OpenStack.

Jenkins failures which showcased this warning message
https://jenkins.ubuntu.com/server/view/cloud-init,%20curtin,%20streams/job/cloud-init-integration-ec2-x/23/console

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:28a042285ad04512a03f611731b455a870c14961
https://jenkins.ubuntu.com/server/job/cloud-init-ci/80/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/80/rebuild

review: Approve (continuous-integration)
Revision history for this message
Ryan Harper (raharper) wrote :

If not already done so, we should update the OpenStack datasource docs to indicate which product strings/chassis ids are used to positively identify OpenStack datasource on VMs and containers.

Revision history for this message
Scott Moser (smoser) wrote :

some minor things.

c84f679... by Chad Smith

address review comments

- magic variables at the top of DataSourceOpenStack
- use util.get_proc_env instead of rolling our own
- add util.is_x86 with efficient string checks for matching
architecture use is_x86 in detect_openstack

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:c84f6798829de3a5b6817057dbea4ba1bdf46081
https://jenkins.ubuntu.com/server/job/cloud-init-ci/87/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/87/rebuild

review: Needs Fixing (continuous-integration)
9c9f6ab... by Chad Smith

add Discovery section to OpenStack datasource RTD

9a475d0... by Chad Smith

doc tweak

2effe5c... by Chad Smith

fix unit tests given use of get_proc_env

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:2effe5c3a1d89c38e3890c2f275046354bfd1b98
https://jenkins.ubuntu.com/server/job/cloud-init-ci/88/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/88/rebuild

review: Needs Fixing (continuous-integration)
44caa4a... by Chad Smith

pyflakes and pycodestyle

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:44caa4afd5810f34091d218638de35c0aa6aaf19
https://jenkins.ubuntu.com/server/job/cloud-init-ci/89/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/89/rebuild

review: Needs Fixing (continuous-integration)
760279f... by Chad Smith

fix unit tests to mock is_x86 instead of uname

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:760279fb794ee510f0bf778c1219bc4def0a15ca
https://jenkins.ubuntu.com/server/job/cloud-init-ci/95/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/95/rebuild

review: Approve (continuous-integration)
Revision history for this message
Scott Moser (smoser) wrote :

trivial suggestions.

Revision history for this message
Ryan Harper (raharper) :
4055f7d... by Chad Smith

use is_x86 in read_dmi_data and add unit test for it

c3183e9... by Chad Smith

define top-level constants VALID_DMI_PRODUCT_NAMES and VALID_DMI_ASSET_TAGS

Revision history for this message
Chad Smith (chad.smith) :
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:c3183e99372292155fd3f9a9124d015d8d9a34dd
https://jenkins.ubuntu.com/server/job/cloud-init-ci/99/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/99/rebuild

review: Approve (continuous-integration)
69b6200... by Chad Smith

doc update

Revision history for this message
Chad Smith (chad.smith) wrote :

Thank you for your merge proposal.

Your branch has been set to 'Work in progress'.
Please set the branch back to 'Needs Review' after resolving the issues below.

Thanks again,
Your friendly neighborhood cloud-init robot.

Please fix the following issues:
------------------------------
Commit message lints:
 - Line #2 has 506 too many characters. Line starts with: "OpenStack datasource"...
------------------------------

For more information, see commit message guidelines at
https://cloudinit.readthedocs.io/en/latest/topics/hacking.html#do-these-things-for-each-feature-or-bug

review: Needs Fixing
Revision history for this message
Chad Smith (chad.smith) wrote :

Thank you for your merge proposal.

Your branch has been set to 'Work in progress'.
Please set the branch back to 'Needs Review' after resolving the issues below.

Thanks again,
Your friendly neighborhood cloud-init robot.

Please fix the following issues:
------------------------------
Commit message lints:
 - Line #2 has 3 too many characters. Line starts with: "OpenStack datasource"... - Line #3 has 4 too many characters. Line starts with: "whether OpenStack metadata"... - Line #4 has 1 too many characters. Line starts with: "setup and metadata probe"... - Line #6 has 3 too many characters. Line starts with: "Cloud-init properly detects"... - Line #7 has 2 too many characters. Line starts with: "probing the metadata"... - Line #9 has 5 too many characters. Line starts with: "get_data will call a"... - Line #10 has 5 too many characters. Line starts with: "platform looks like OpenStack"...
------------------------------

For more information, see commit message guidelines at
https://cloudinit.readthedocs.io/en/latest/topics/hacking.html#do-these-things-for-each-feature-or-bug

review: Needs Fixing
Revision history for this message
Scott Moser (smoser) :
review: Approve
8266327... by Chad Smith

proper mock of get_proc_env in unit tests

Revision history for this message
Chad Smith (chad.smith) :
review: Abstain
Revision history for this message
Chad Smith (chad.smith) wrote :

An upstream commit landed for this bug.

To view that commit see the following URL:
https://git.launchpad.net/cloud-init/commit/?id=1efa8a0a

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cloudinit/sources/DataSourceOpenStack.py b/cloudinit/sources/DataSourceOpenStack.py
2index 1a12a3f..365af96 100644
3--- a/cloudinit/sources/DataSourceOpenStack.py
4+++ b/cloudinit/sources/DataSourceOpenStack.py
5@@ -23,6 +23,13 @@ DEFAULT_METADATA = {
6 "instance-id": DEFAULT_IID,
7 }
8
9+# OpenStack DMI constants
10+DMI_PRODUCT_NOVA = 'OpenStack Nova'
11+DMI_PRODUCT_COMPUTE = 'OpenStack Compute'
12+VALID_DMI_PRODUCT_NAMES = [DMI_PRODUCT_NOVA, DMI_PRODUCT_COMPUTE]
13+DMI_ASSET_TAG_OPENTELEKOM = 'OpenTelekomCloud'
14+VALID_DMI_ASSET_TAGS = [DMI_ASSET_TAG_OPENTELEKOM]
15+
16
17 class DataSourceOpenStack(openstack.SourceMixin, sources.DataSource):
18
19@@ -114,6 +121,8 @@ class DataSourceOpenStack(openstack.SourceMixin, sources.DataSource):
20 False when unable to contact metadata service or when metadata
21 format is invalid or disabled.
22 """
23+ if not detect_openstack():
24+ return False
25 if self.perform_dhcp_setup: # Setup networking in init-local stage.
26 try:
27 with EphemeralDHCPv4(self.fallback_interface):
28@@ -205,6 +214,20 @@ def read_metadata_service(base_url, ssl_details=None,
29 return reader.read_v2()
30
31
32+def detect_openstack():
33+ """Return True when a potential OpenStack platform is detected."""
34+ if not util.is_x86():
35+ return True # Non-Intel cpus don't properly report dmi product names
36+ product_name = util.read_dmi_data('system-product-name')
37+ if product_name in VALID_DMI_PRODUCT_NAMES:
38+ return True
39+ elif util.read_dmi_data('chassis-asset-tag') in VALID_DMI_ASSET_TAGS:
40+ return True
41+ elif util.get_proc_env(1).get('product_name') == DMI_PRODUCT_NOVA:
42+ return True
43+ return False
44+
45+
46 # Used to match classes to dependencies
47 datasources = [
48 (DataSourceOpenStackLocal, (sources.DEP_FILESYSTEM,)),
49diff --git a/cloudinit/util.py b/cloudinit/util.py
50index 26a4112..6da9511 100644
51--- a/cloudinit/util.py
52+++ b/cloudinit/util.py
53@@ -2629,6 +2629,16 @@ def _call_dmidecode(key, dmidecode_path):
54 return None
55
56
57+def is_x86(uname_arch=None):
58+ """Return True if platform is x86-based"""
59+ if uname_arch is None:
60+ uname_arch = os.uname()[4]
61+ x86_arch_match = (
62+ uname_arch == 'x86_64' or
63+ (uname_arch[0] == 'i' and uname_arch[2:] == '86'))
64+ return x86_arch_match
65+
66+
67 def read_dmi_data(key):
68 """
69 Wrapper for reading DMI data.
70@@ -2656,8 +2666,7 @@ def read_dmi_data(key):
71
72 # running dmidecode can be problematic on some arches (LP: #1243287)
73 uname_arch = os.uname()[4]
74- if not (uname_arch == "x86_64" or
75- (uname_arch.startswith("i") and uname_arch[2:] == "86") or
76+ if not (is_x86(uname_arch) or
77 uname_arch == 'aarch64' or
78 uname_arch == 'amd64'):
79 LOG.debug("dmidata is not supported on %s", uname_arch)
80diff --git a/doc/rtd/topics/datasources/openstack.rst b/doc/rtd/topics/datasources/openstack.rst
81index 0ea8994..421da08 100644
82--- a/doc/rtd/topics/datasources/openstack.rst
83+++ b/doc/rtd/topics/datasources/openstack.rst
84@@ -7,6 +7,21 @@ This datasource supports reading data from the
85 `OpenStack Metadata Service
86 <https://docs.openstack.org/nova/latest/admin/networking-nova.html#metadata-service>`_.
87
88+Discovery
89+-------------
90+To determine whether a platform looks like it may be OpenStack, cloud-init
91+checks the following environment attributes as a potential OpenStack platform:
92+
93+ * Maybe OpenStack if
94+
95+ * **non-x86 cpu architecture**: because DMI data is buggy on some arches
96+ * Is OpenStack **if x86 architecture and ANY** of the following
97+
98+ * **/proc/1/environ**: Nova-lxd contains *product_name=OpenStack Nova*
99+ * **DMI product_name**: Either *Openstack Nova* or *OpenStack Compute*
100+ * **DMI chassis_asset_tag** is *OpenTelekomCloud*
101+
102+
103 Configuration
104 -------------
105 The following configuration can be set for the datasource in system
106diff --git a/tests/unittests/test_datasource/test_openstack.py b/tests/unittests/test_datasource/test_openstack.py
107index fad73b2..585acc3 100644
108--- a/tests/unittests/test_datasource/test_openstack.py
109+++ b/tests/unittests/test_datasource/test_openstack.py
110@@ -69,6 +69,8 @@ EC2_VERSIONS = [
111 'latest',
112 ]
113
114+MOCK_PATH = 'cloudinit.sources.DataSourceOpenStack.'
115+
116
117 # TODO _register_uris should leverage test_ec2.register_mock_metaserver.
118 def _register_uris(version, ec2_files, ec2_meta, os_files):
119@@ -231,7 +233,10 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
120 ds_os = ds.DataSourceOpenStack(
121 settings.CFG_BUILTIN, None, helpers.Paths({'run_dir': self.tmp}))
122 self.assertIsNone(ds_os.version)
123- found = ds_os.get_data()
124+ mock_path = MOCK_PATH + 'detect_openstack'
125+ with test_helpers.mock.patch(mock_path) as m_detect_os:
126+ m_detect_os.return_value = True
127+ found = ds_os.get_data()
128 self.assertTrue(found)
129 self.assertEqual(2, ds_os.version)
130 md = dict(ds_os.metadata)
131@@ -260,7 +265,10 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
132 'broadcast-address': '192.168.2.255'}]
133
134 self.assertIsNone(ds_os_local.version)
135- found = ds_os_local.get_data()
136+ mock_path = MOCK_PATH + 'detect_openstack'
137+ with test_helpers.mock.patch(mock_path) as m_detect_os:
138+ m_detect_os.return_value = True
139+ found = ds_os_local.get_data()
140 self.assertTrue(found)
141 self.assertEqual(2, ds_os_local.version)
142 md = dict(ds_os_local.metadata)
143@@ -284,7 +292,10 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
144 None,
145 helpers.Paths({'run_dir': self.tmp}))
146 self.assertIsNone(ds_os.version)
147- found = ds_os.get_data()
148+ mock_path = MOCK_PATH + 'detect_openstack'
149+ with test_helpers.mock.patch(mock_path) as m_detect_os:
150+ m_detect_os.return_value = True
151+ found = ds_os.get_data()
152 self.assertFalse(found)
153 self.assertIsNone(ds_os.version)
154 self.assertIn(
155@@ -306,15 +317,16 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
156 'timeout': 0,
157 }
158 self.assertIsNone(ds_os.version)
159- found = ds_os.get_data()
160+ mock_path = MOCK_PATH + 'detect_openstack'
161+ with test_helpers.mock.patch(mock_path) as m_detect_os:
162+ m_detect_os.return_value = True
163+ found = ds_os.get_data()
164 self.assertFalse(found)
165 self.assertIsNone(ds_os.version)
166
167 def test_network_config_disabled_by_datasource_config(self):
168 """The network_config can be disabled from datasource config."""
169- mock_path = (
170- 'cloudinit.sources.DataSourceOpenStack.openstack.'
171- 'convert_net_json')
172+ mock_path = MOCK_PATH + 'openstack.convert_net_json'
173 ds_os = ds.DataSourceOpenStack(
174 settings.CFG_BUILTIN, None, helpers.Paths({'run_dir': self.tmp}))
175 ds_os.ds_cfg = {'apply_network_config': False}
176@@ -327,9 +339,7 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
177
178 def test_network_config_from_network_json(self):
179 """The datasource gets network_config from network_data.json."""
180- mock_path = (
181- 'cloudinit.sources.DataSourceOpenStack.openstack.'
182- 'convert_net_json')
183+ mock_path = MOCK_PATH + 'openstack.convert_net_json'
184 example_cfg = {'version': 1, 'config': []}
185 ds_os = ds.DataSourceOpenStack(
186 settings.CFG_BUILTIN, None, helpers.Paths({'run_dir': self.tmp}))
187@@ -345,9 +355,7 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
188
189 def test_network_config_cached(self):
190 """The datasource caches the network_config property."""
191- mock_path = (
192- 'cloudinit.sources.DataSourceOpenStack.openstack.'
193- 'convert_net_json')
194+ mock_path = MOCK_PATH + 'openstack.convert_net_json'
195 example_cfg = {'version': 1, 'config': []}
196 ds_os = ds.DataSourceOpenStack(
197 settings.CFG_BUILTIN, None, helpers.Paths({'run_dir': self.tmp}))
198@@ -374,7 +382,10 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
199 'timeout': 0,
200 }
201 self.assertIsNone(ds_os.version)
202- found = ds_os.get_data()
203+ mock_path = MOCK_PATH + 'detect_openstack'
204+ with test_helpers.mock.patch(mock_path) as m_detect_os:
205+ m_detect_os.return_value = True
206+ found = ds_os.get_data()
207 self.assertFalse(found)
208 self.assertIsNone(ds_os.version)
209
210@@ -438,4 +449,89 @@ class TestVendorDataLoading(test_helpers.TestCase):
211 data = {'foo': 'bar', 'cloud-init': ['VD_1', 'VD_2']}
212 self.assertEqual(self.cvj(data), data['cloud-init'])
213
214+
215+@test_helpers.mock.patch(MOCK_PATH + 'util.is_x86')
216+class TestDetectOpenStack(test_helpers.CiTestCase):
217+
218+ def test_detect_openstack_non_intel_x86(self, m_is_x86):
219+ """Return True on non-intel platforms because dmi isn't conclusive."""
220+ m_is_x86.return_value = False
221+ self.assertTrue(
222+ ds.detect_openstack(), 'Expected detect_openstack == True')
223+
224+ @test_helpers.mock.patch(MOCK_PATH + 'util.get_proc_env')
225+ @test_helpers.mock.patch(MOCK_PATH + 'util.read_dmi_data')
226+ def test_not_detect_openstack_intel_x86_ec2(self, m_dmi, m_proc_env,
227+ m_is_x86):
228+ """Return False on EC2 platforms."""
229+ m_is_x86.return_value = True
230+ # No product_name in proc/1/environ
231+ m_proc_env.return_value = {'HOME': '/'}
232+
233+ def fake_dmi_read(dmi_key):
234+ if dmi_key == 'system-product-name':
235+ return 'HVM domU' # Nothing 'openstackish' on EC2
236+ if dmi_key == 'chassis-asset-tag':
237+ return '' # Empty string on EC2
238+ assert False, 'Unexpected dmi read of %s' % dmi_key
239+
240+ m_dmi.side_effect = fake_dmi_read
241+ self.assertFalse(
242+ ds.detect_openstack(), 'Expected detect_openstack == False on EC2')
243+ m_proc_env.assert_called_with(1)
244+
245+ @test_helpers.mock.patch(MOCK_PATH + 'util.read_dmi_data')
246+ def test_detect_openstack_intel_product_name_compute(self, m_dmi,
247+ m_is_x86):
248+ """Return True on OpenStack compute and nova instances."""
249+ m_is_x86.return_value = True
250+ openstack_product_names = ['OpenStack Nova', 'OpenStack Compute']
251+
252+ for product_name in openstack_product_names:
253+ m_dmi.return_value = product_name
254+ self.assertTrue(
255+ ds.detect_openstack(), 'Failed to detect_openstack')
256+
257+ @test_helpers.mock.patch(MOCK_PATH + 'util.read_dmi_data')
258+ def test_detect_openstack_opentelekomcloud_chassis_asset_tag(self, m_dmi,
259+ m_is_x86):
260+ """Return True on OpenStack reporting OpenTelekomCloud asset-tag."""
261+ m_is_x86.return_value = True
262+
263+ def fake_dmi_read(dmi_key):
264+ if dmi_key == 'system-product-name':
265+ return 'HVM domU' # Nothing 'openstackish' on OpenTelekomCloud
266+ if dmi_key == 'chassis-asset-tag':
267+ return 'OpenTelekomCloud'
268+ assert False, 'Unexpected dmi read of %s' % dmi_key
269+
270+ m_dmi.side_effect = fake_dmi_read
271+ self.assertTrue(
272+ ds.detect_openstack(),
273+ 'Expected detect_openstack == True on OpenTelekomCloud')
274+
275+ @test_helpers.mock.patch(MOCK_PATH + 'util.get_proc_env')
276+ @test_helpers.mock.patch(MOCK_PATH + 'util.read_dmi_data')
277+ def test_detect_openstack_by_proc_1_environ(self, m_dmi, m_proc_env,
278+ m_is_x86):
279+ """Return True when nova product_name specified in /proc/1/environ."""
280+ m_is_x86.return_value = True
281+ # Nova product_name in proc/1/environ
282+ m_proc_env.return_value = {
283+ 'HOME': '/', 'product_name': 'OpenStack Nova'}
284+
285+ def fake_dmi_read(dmi_key):
286+ if dmi_key == 'system-product-name':
287+ return 'HVM domU' # Nothing 'openstackish'
288+ if dmi_key == 'chassis-asset-tag':
289+ return '' # Nothin 'openstackish'
290+ assert False, 'Unexpected dmi read of %s' % dmi_key
291+
292+ m_dmi.side_effect = fake_dmi_read
293+ self.assertTrue(
294+ ds.detect_openstack(),
295+ 'Expected detect_openstack == True on OpenTelekomCloud')
296+ m_proc_env.assert_called_with(1)
297+
298+
299 # vi: ts=4 expandtab
300diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
301index 20479f6..7a203ce 100644
302--- a/tests/unittests/test_util.py
303+++ b/tests/unittests/test_util.py
304@@ -468,6 +468,29 @@ class TestMountinfoParsing(helpers.ResourceUsingTestCase):
305 self.assertIsNone(ret)
306
307
308+class TestIsX86(helpers.CiTestCase):
309+
310+ def test_is_x86_matches_x86_types(self):
311+ """is_x86 returns True if CPU architecture matches."""
312+ matched_arches = ['x86_64', 'i386', 'i586', 'i686']
313+ for arch in matched_arches:
314+ self.assertTrue(
315+ util.is_x86(arch), 'Expected is_x86 for arch "%s"' % arch)
316+
317+ def test_is_x86_unmatched_types(self):
318+ """is_x86 returns Fale on non-intel x86 architectures."""
319+ unmatched_arches = ['ia64', '9000/800', 'arm64v71']
320+ for arch in unmatched_arches:
321+ self.assertFalse(
322+ util.is_x86(arch), 'Expected not is_x86 for arch "%s"' % arch)
323+
324+ @mock.patch('cloudinit.util.os.uname')
325+ def test_is_x86_calls_uname_for_architecture(self, m_uname):
326+ """is_x86 returns True if platform from uname matches."""
327+ m_uname.return_value = [0, 1, 2, 3, 'x86_64']
328+ self.assertTrue(util.is_x86())
329+
330+
331 class TestReadDMIData(helpers.FilesystemMockingTestCase):
332
333 def setUp(self):

Subscribers

People subscribed via source and target branches