Merge ~rjschwei/cloud-init:noLnxDistro into cloud-init:master
- Git
- lp:~rjschwei/cloud-init
- noLnxDistro
- Merge into master
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) |
||||
Related bugs: |
|
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
Server Team CI bot (server-team-bot) wrote : | # |
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:cffee0de498
https:/
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:/
Chad Smith (chad.smith) : | # |
Chad Smith (chad.smith) wrote : | # |
I'm not I don't think we can store any non-dict values in the directory /etc/cloud/
If we have one offs that you want to store somewhere else, maybe just in /etc/cloud/
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.
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:84bcc3cab32
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:923d318ed76
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:9edca71ca9f
https:/
Executed test runs:
SUCCESS: Checkout
FAILED: Unit & Style Tests
Click here to trigger a rebuild:
https:/
Robert Schweikert (rjschwei) wrote : | # |
> I'm not I don't think we can store any non-dict values in the directory
> /etc/cloud/
> 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/
> /cloud-
>
> 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
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:36c6158eb41
https:/
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:/
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/
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.
Chad Smith (chad.smith) : | # |
Robert Schweikert (rjschwei) wrote : | # |
Should be all set now.
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:a0c044737f0
https:/
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:/
Chad Smith (chad.smith) wrote : | # |
Thank you for this rework Robert. LGTM!
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:/
Chad Smith (chad.smith) wrote : | # |
oops sorry robert, automation snafu. fixing and landing
Chad Smith (chad.smith) : | # |
Chad Smith (chad.smith) wrote : | # |
An upstream commit landed for this bug.
To view that commit see the following URL:
https:/
Preview Diff
1 | diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py |
2 | index 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 |
106 | diff --git a/cloudinit/util.py b/cloudinit/util.py |
107 | index 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' |
173 | diff --git a/setup.py b/setup.py |
174 | index 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 |
PASSED: Continuous integration, rev:3c1a518f968 a0f4caa30dedd42 72a60067768ddf /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 745/
https:/
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: /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 745/rebuild
https:/