Merge ~rjschwei/cloud-init:noLnxDistro into cloud-init:master

Proposed by Robert Schweikert
Status: Merged
Approved by: Chad Smith
Approved revision: a0c044737f0557bde3627869dc0436c8ab47d6e6
Merge reported by: Chad Smith
Merged at revision: bbcc5e82e6c8e87ca483150205127cb0436c4cd9
Proposed branch: ~rjschwei/cloud-init:noLnxDistro
Merge into: cloud-init:master
Diff against target: 222 lines (+127/-7)
3 files modified
cloudinit/tests/test_util.py (+77/-1)
cloudinit/util.py (+36/-3)
setup.py (+14/-3)
Reviewer Review Type Date Requested Status
Chad Smith Approve
Server Team CI bot continuous-integration Approve
Review via email: mp+336794@code.launchpad.net

Commit message

util: add get_linux_distro function to replace platform.dist

Allow the user to set the distribution with --distro argument to setup.py.
Fall back is to read /etc/os-release. Final backup is to use
platform.dist() Python function. The platform.dist() function is
deprecated and will be removed in Python 3.7

LP: #1745235

Description of the change

util: add get_linux_distro function to replace platform.dist

Allow the user to set the distribution with --distro argument to setup.py. Fall back is to read /etc/os-release. Final backup is to use platform.dist() Python function. The platform.dist() function is deprecated and will be removed in Python 3.7

LP: #1745235

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:3c1a518f968a0f4caa30dedd4272a60067768ddf
https://jenkins.ubuntu.com/server/job/cloud-init-ci/745/
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/745/rebuild

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

PASSED: Continuous integration, rev:cffee0de4985ea15e038a439c7f670409614db72
https://jenkins.ubuntu.com/server/job/cloud-init-ci/746/
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/746/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) :
Revision history for this message
Chad Smith (chad.smith) wrote :

I'm not I don't think we can store any non-dict values in the directory /etc/cloud/cloud.cfg.d/ because all files there are ultimately merged together in a giant system_config dictionary against which all of cloud-init runs.

If we have one offs that you want to store somewhere else, maybe just in /etc/cloud/<filename>, otherwise we risk tracebacks like this in /var/log/cloud-init-output.log

2018-05-14 22:14:46,663 - util.py[WARNING]: Failed loading yaml blob

I'm not really certain why we want to provide a facility for an image to override the distribution detection anyway with a config file on the image. Why not just make sure cloud-init detects properly the system on which it is running? Also, we do have a system_info: distro: <distro-name> config option which affects what underlying distro is selected by cloud-init and it feels like providing this additional mechanism is a bit confusing.

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

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Schweikert (rjschwei) wrote :

> I'm not I don't think we can store any non-dict values in the directory
> /etc/cloud/cloud.cfg.d/ because all files there are ultimately merged together
> in a giant system_config dictionary against which all of cloud-init runs.
>
> If we have one offs that you want to store somewhere else, maybe just in
> /etc/cloud/<filename>, otherwise we risk tracebacks like this in /var/log
> /cloud-init-output.log
>
> 2018-05-14 22:14:46,663 - util.py[WARNING]: Failed loading yaml blob
>
> I'm not really certain why we want to provide a facility for an image to
> override the distribution detection anyway with a config file on the image.
> Why not just make sure cloud-init detects properly the system on which it is
> running? Also, we do have a system_info: distro: <distro-name> config option
> which affects what underlying distro is selected by cloud-init and it feels
> like providing this additional mechanism is a bit confusing.

Scott requested that a method be provided for the user to override the "default" behavior. Thus if we allow the user to override the behavior at build time we have to know if the user did this in case any issues are reported. Therefore the value has to be persisted. If we do not persist the value and we get a question bug report and the config option "system_info: distro: <distro-name>" and the templates do not match the answer can only be "we do not why this happened". But if the file exists then we can say "someone overrode the distro detection mechanism during build"

I moved the file to /etc/cloud

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

PASSED: Continuous integration, rev:36c6158eb4151d37fecd53ac94b07bde721ee339
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1124/
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/1124/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) wrote :

Robert, thanks for the fixes. I understand wanting to override at distro at build time and ensuring that config templates are properly generated for the target environment. What I'm not to certain about is the overriding dynamic get_linux_distro().

We had a meeting to discuss how we want to approach overriding dyanamic distro detection in your new get_linux_distro function.

I think we want to drop modifying runtime behavior from this branch until we sort a better way to override default behavior of get_linux_distro and correlate that potentially with which cloudinit.distro class if chosen as well.

As you mentioned in IRC, you can reserve the "I told you so" card for when this approach doesn't fly :)

Ultimately, we want to move the ability override distro-detection up to a higher level which has access to the consolidated system_cfg:distro as defined in /etc/cloud/cloud-cfg.d. We've also discussed the possibility of allowing a system_cfg: distro: 'auto' which would enable distro-class auto-detection using your get_linux_distro() versus a static config override from /etc/cloud/cloud.cfg

These approaches are something that will involve a bit more back and forth as far as design, so let's keep this branch simple so we can land it without the inevitable bikeshed when designing the right overridden behavior.

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

Should be all set now.

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

PASSED: Continuous integration, rev:a0c044737f0557bde3627869dc0436c8ab47d6e6
https://jenkins.ubuntu.com/server/job/cloud-init-ci/11/
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/11/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) wrote :

Thank you for this rework Robert. LGTM!

review: Approve
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 171 too many characters. Line starts with: "Allow the user to set"...
------------------------------

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 :

oops sorry robert, automation snafu. fixing and landing

Revision history for this message
Chad Smith (chad.smith) :
review: Approve
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=bbcc5e82

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py
2index 3c05a43..17853fc 100644
3--- a/cloudinit/tests/test_util.py
4+++ b/cloudinit/tests/test_util.py
5@@ -3,11 +3,12 @@
6 """Tests for cloudinit.util"""
7
8 import logging
9-from textwrap import dedent
10+import platform
11
12 import cloudinit.util as util
13
14 from cloudinit.tests.helpers import CiTestCase, mock
15+from textwrap import dedent
16
17 LOG = logging.getLogger(__name__)
18
19@@ -16,6 +17,29 @@ MOUNT_INFO = [
20 '153 68 254:0 / /home rw,relatime shared:101 - xfs /dev/sda2 rw,attr2'
21 ]
22
23+OS_RELEASE_SLES = dedent("""\
24+ NAME="SLES"\n
25+ VERSION="12-SP3"\n
26+ VERSION_ID="12.3"\n
27+ PRETTY_NAME="SUSE Linux Enterprise Server 12 SP3"\n
28+ ID="sles"\nANSI_COLOR="0;32"\n
29+ CPE_NAME="cpe:/o:suse:sles:12:sp3"\n
30+""")
31+
32+OS_RELEASE_UBUNTU = dedent("""\
33+ NAME="Ubuntu"\n
34+ VERSION="16.04.3 LTS (Xenial Xerus)"\n
35+ ID=ubuntu\n
36+ ID_LIKE=debian\n
37+ PRETTY_NAME="Ubuntu 16.04.3 LTS"\n
38+ VERSION_ID="16.04"\n
39+ HOME_URL="http://www.ubuntu.com/"\n
40+ SUPPORT_URL="http://help.ubuntu.com/"\n
41+ BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"\n
42+ VERSION_CODENAME=xenial\n
43+ UBUNTU_CODENAME=xenial\n
44+""")
45+
46
47 class FakeCloud(object):
48
49@@ -261,4 +285,56 @@ class TestUdevadmSettle(CiTestCase):
50 self.assertRaises(util.ProcessExecutionError, util.udevadm_settle)
51
52
53+@mock.patch('os.path.exists')
54+class TestGetLinuxDistro(CiTestCase):
55+
56+ @classmethod
57+ def os_release_exists(self, path):
58+ """Side effect function"""
59+ if path == '/etc/os-release':
60+ return 1
61+
62+ @mock.patch('cloudinit.util.load_file')
63+ def test_get_linux_distro_quoted_name(self, m_os_release, m_path_exists):
64+ """Verify we get the correct name if the os-release file has
65+ the distro name in quotes"""
66+ m_os_release.return_value = OS_RELEASE_SLES
67+ m_path_exists.side_effect = TestGetLinuxDistro.os_release_exists
68+ dist = util.get_linux_distro()
69+ self.assertEqual(('sles', '12.3', platform.machine()), dist)
70+
71+ @mock.patch('cloudinit.util.load_file')
72+ def test_get_linux_distro_bare_name(self, m_os_release, m_path_exists):
73+ """Verify we get the correct name if the os-release file does not
74+ have the distro name in quotes"""
75+ m_os_release.return_value = OS_RELEASE_UBUNTU
76+ m_path_exists.side_effect = TestGetLinuxDistro.os_release_exists
77+ dist = util.get_linux_distro()
78+ self.assertEqual(('ubuntu', '16.04', platform.machine()), dist)
79+
80+ @mock.patch('platform.dist')
81+ def test_get_linux_distro_no_data(self, m_platform_dist, m_path_exists):
82+ """Verify we get no information if os-release does not exist"""
83+ m_platform_dist.return_value = ('', '', '')
84+ m_path_exists.return_value = 0
85+ dist = util.get_linux_distro()
86+ self.assertEqual(('', '', ''), dist)
87+
88+ @mock.patch('platform.dist')
89+ def test_get_linux_distro_no_impl(self, m_platform_dist, m_path_exists):
90+ """Verify we get an empty tuple when no information exists and
91+ Exceptions are not propagated"""
92+ m_platform_dist.side_effect = Exception()
93+ m_path_exists.return_value = 0
94+ dist = util.get_linux_distro()
95+ self.assertEqual(('', '', ''), dist)
96+
97+ @mock.patch('platform.dist')
98+ def test_get_linux_distro_plat_data(self, m_platform_dist, m_path_exists):
99+ """Verify we get the correct platform information"""
100+ m_platform_dist.return_value = ('foo', '1.1', 'aarch64')
101+ m_path_exists.return_value = 0
102+ dist = util.get_linux_distro()
103+ self.assertEqual(('foo', '1.1', 'aarch64'), dist)
104+
105 # vi: ts=4 expandtab
106diff --git a/cloudinit/util.py b/cloudinit/util.py
107index edfedc7..e7b5bc7 100644
108--- a/cloudinit/util.py
109+++ b/cloudinit/util.py
110@@ -576,6 +576,39 @@ def get_cfg_option_int(yobj, key, default=0):
111 return int(get_cfg_option_str(yobj, key, default=default))
112
113
114+def get_linux_distro():
115+ distro_name = ''
116+ distro_version = ''
117+ if os.path.exists('/etc/os-release'):
118+ os_release = load_file('/etc/os-release')
119+ for line in os_release.splitlines():
120+ if line.strip().startswith('ID='):
121+ distro_name = line.split('=')[-1]
122+ distro_name = distro_name.replace('"', '')
123+ if line.strip().startswith('VERSION_ID='):
124+ # Lets hope for the best that distros stay consistent ;)
125+ distro_version = line.split('=')[-1]
126+ distro_version = distro_version.replace('"', '')
127+ else:
128+ dist = ('', '', '')
129+ try:
130+ # Will be removed in 3.7
131+ dist = platform.dist() # pylint: disable=W1505
132+ except Exception:
133+ pass
134+ finally:
135+ found = None
136+ for entry in dist:
137+ if entry:
138+ found = 1
139+ if not found:
140+ LOG.warning('Unable to determine distribution, template '
141+ 'expansion may have unexpected results')
142+ return dist
143+
144+ return (distro_name, distro_version, platform.machine())
145+
146+
147 def system_info():
148 info = {
149 'platform': platform.platform(),
150@@ -583,19 +616,19 @@ def system_info():
151 'release': platform.release(),
152 'python': platform.python_version(),
153 'uname': platform.uname(),
154- 'dist': platform.dist(), # pylint: disable=W1505
155+ 'dist': get_linux_distro()
156 }
157 system = info['system'].lower()
158 var = 'unknown'
159 if system == "linux":
160 linux_dist = info['dist'][0].lower()
161- if linux_dist in ('centos', 'fedora', 'debian'):
162+ if linux_dist in ('centos', 'debian', 'fedora', 'rhel', 'suse'):
163 var = linux_dist
164 elif linux_dist in ('ubuntu', 'linuxmint', 'mint'):
165 var = 'ubuntu'
166 elif linux_dist == 'redhat':
167 var = 'rhel'
168- elif linux_dist == 'suse':
169+ elif linux_dist in ('opensuse', 'sles'):
170 var = 'suse'
171 else:
172 var = 'linux'
173diff --git a/setup.py b/setup.py
174index 85b2337..5ed8eae 100755
175--- a/setup.py
176+++ b/setup.py
177@@ -25,7 +25,7 @@ from distutils.errors import DistutilsArgError
178 import subprocess
179
180 RENDERED_TMPD_PREFIX = "RENDERED_TEMPD"
181-
182+VARIANT = None
183
184 def is_f(p):
185 return os.path.isfile(p)
186@@ -114,10 +114,20 @@ def render_tmpl(template):
187 atexit.register(shutil.rmtree, tmpd)
188 bname = os.path.basename(template).rstrip(tmpl_ext)
189 fpath = os.path.join(tmpd, bname)
190- tiny_p([sys.executable, './tools/render-cloudcfg', template, fpath])
191+ if VARIANT:
192+ tiny_p([sys.executable, './tools/render-cloudcfg', '--variant',
193+ VARIANT, template, fpath])
194+ else:
195+ tiny_p([sys.executable, './tools/render-cloudcfg', template, fpath])
196 # return path relative to setup.py
197 return os.path.join(os.path.basename(tmpd), bname)
198
199+# User can set the variant for template rendering
200+if '--distro' in sys.argv:
201+ idx = sys.argv.index('--distro')
202+ VARIANT = sys.argv[idx+1]
203+ del sys.argv[idx+1]
204+ sys.argv.remove('--distro')
205
206 INITSYS_FILES = {
207 'sysvinit': [f for f in glob('sysvinit/redhat/*') if is_f(f)],
208@@ -260,7 +270,7 @@ requirements = read_requires()
209 setuptools.setup(
210 name='cloud-init',
211 version=get_version(),
212- description='EC2 initialisation magic',
213+ description='Cloud instance initialisation magic',
214 author='Scott Moser',
215 author_email='scott.moser@canonical.com',
216 url='http://launchpad.net/cloud-init/',
217@@ -277,4 +287,5 @@ setuptools.setup(
218 }
219 )
220
221+
222 # vi: ts=4 expandtab

Subscribers

People subscribed via source and target branches