Merge lp:~sankaraditya/cloud-init/topic-stanguturi-vmware-support into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Sankar Tanguturi on 2016-03-08
Status: Merged
Merged at revision: 1186
Proposed branch: lp:~sankaraditya/cloud-init/topic-stanguturi-vmware-support
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 330 lines (+251/-10)
6 files modified
cloudinit/sources/DataSourceOVF.py (+45/-9)
cloudinit/sources/helpers/vmware/imc/config_nic.py (+2/-1)
cloudinit/sources/helpers/vmware/imc/guestcust_error.py (+24/-0)
cloudinit/sources/helpers/vmware/imc/guestcust_event.py (+27/-0)
cloudinit/sources/helpers/vmware/imc/guestcust_state.py (+25/-0)
cloudinit/sources/helpers/vmware/imc/guestcust_util.py (+128/-0)
To merge this branch: bzr merge lp:~sankaraditya/cloud-init/topic-stanguturi-vmware-support
Reviewer Review Type Date Requested Status
Scott Moser 2016-03-08 Needs Fixing on 2016-03-11
Review via email: mp+288452@code.launchpad.net

Commit Message

Send proper SUCCESS / FAILED events to the underlying VMware hypervisor.

Added code to customize timezone.
Added few utility functions to send events to the VMware hypervisor.
Re-factored the code little bit.
Added code to send SUCCESS event when customization succeeds.
Added code to send FAILED event if any error occurs during customization.

Description of the Change

Added some utility functions to report some events to the
underlying VMware Virtualization Platform.

To post a comment you must log in.
1167. By Sankar Tanguturi <stanguturi@stanguturi-rhel> on 2016-03-10

 - Fixed few issues with return values form util.subp()
 - Added a new utility method to send a RPC for enabling NICS
 - Modified DataSourceOVF.py to enable nics.
 - Executed ./tools/run-pep8 and no issues were reported.

Sankar Tanguturi (sankaraditya) wrote :

Fixed few issues. Added new utility function. No pep8 errors are reported. Updated the diff. Thanks.

Scott Moser (smoser) wrote :

some initial comments. have not had time to fully review.

review: Needs Fixing
Sankar Tanguturi (sankaraditya) wrote :

> some initial comments. have not had time to fully review.
Thanks Scott. I executed 'bzr merge' in my branch and resolved all the conflicts. Do I need to execute 'bzr commit' and 'bzr push' after resolving?

1168. By Sankar Tanguturi <stanguturi@stanguturi-rhel> on 2016-03-11

- Executed 'bzr merge' and resolved all the conflicts.
- Now my branch is identical to trunk.dist

1169. By Sankar Tanguturi <stanguturi@stanguturi-rhel> on 2016-03-11

 - Fixed few pep8 and flake8 issues.
 - Changed the really long 'from ... import ...' statements.

Sankar Tanguturi (sankaraditya) wrote :

Fixed the merge issues. Fixed the pep8 and flake8 issues. Updated the diff. Thanks

1170. By Sankar Tanguturi <stanguturi@stanguturi-rhel> on 2016-03-16

 - Added the code to customize timezone.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cloudinit/sources/DataSourceOVF.py'
2--- cloudinit/sources/DataSourceOVF.py 2016-03-04 06:55:28 +0000
3+++ cloudinit/sources/DataSourceOVF.py 2016-03-16 00:29:03 +0000
4@@ -31,9 +31,17 @@
5 from cloudinit import log as logging
6 from cloudinit import sources
7 from cloudinit import util
8-from cloudinit.sources.helpers.vmware.imc.config import Config
9-from cloudinit.sources.helpers.vmware.imc.config_file import ConfigFile
10-from cloudinit.sources.helpers.vmware.imc.config_nic import NicConfigurator
11+from .helpers.vmware.imc.config import Config
12+from .helpers.vmware.imc.config_file import ConfigFile
13+from .helpers.vmware.imc.config_nic import NicConfigurator
14+from .helpers.vmware.imc.guestcust_event import GuestCustEventEnum
15+from .helpers.vmware.imc.guestcust_state import GuestCustStateEnum
16+from .helpers.vmware.imc.guestcust_error import GuestCustErrorEnum
17+from .helpers.vmware.imc.guestcust_util import (
18+ set_customization_status,
19+ get_nics_to_enable,
20+ enable_nics
21+)
22
23 LOG = logging.getLogger(__name__)
24
25@@ -73,6 +81,9 @@
26 self.sys_cfg, "disable_vmware_customization", True):
27 deployPkgPluginPath = search_file("/usr/lib/vmware-tools",
28 "libdeployPkgPlugin.so")
29+ if not deployPkgPluginPath:
30+ deployPkgPluginPath = search_file("/usr/lib/open-vm-tools",
31+ "libdeployPkgPlugin.so")
32 if deployPkgPluginPath:
33 vmwareImcConfigFilePath = util.log_time(
34 logfunc=LOG.debug,
35@@ -88,19 +99,41 @@
36 LOG.debug("Customization for VMware platform is disabled.")
37
38 if vmwareImcConfigFilePath:
39+ nics = ""
40 try:
41 cf = ConfigFile(vmwareImcConfigFilePath)
42 conf = Config(cf)
43 (md, ud, cfg) = read_vmware_imc(conf)
44- nicConfigurator = NicConfigurator(conf.nics)
45- nicConfigurator.configure()
46- vmwarePlatformFound = True
47- except Exception as inst:
48- LOG.debug("Error while parsing the Customization "
49- "Config File: %s", inst)
50+ dirpath = os.path.dirname(vmwareImcConfigFilePath)
51+ nics = get_nics_to_enable(dirpath)
52+ except Exception as e:
53+ LOG.debug("Error parsing the customization Config File")
54+ LOG.exception(e)
55+ set_customization_status(
56+ GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
57+ GuestCustEventEnum.GUESTCUST_EVENT_CUSTOMIZE_FAILED)
58+ return False
59 finally:
60 dirPath = os.path.dirname(vmwareImcConfigFilePath)
61 shutil.rmtree(dirPath)
62+
63+ try:
64+ LOG.debug("Applying the Network customization")
65+ nicConfigurator = NicConfigurator(conf.nics)
66+ nicConfigurator.configure()
67+ except Exception as e:
68+ LOG.debug("Error applying the Network Configuration")
69+ LOG.exception(e)
70+ set_customization_status(
71+ GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
72+ GuestCustEventEnum.GUESTCUST_EVENT_NETWORK_SETUP_FAILED)
73+ return False
74+
75+ vmwarePlatformFound = True
76+ enable_nics(nics)
77+ set_customization_status(
78+ GuestCustStateEnum.GUESTCUST_STATE_DONE,
79+ GuestCustErrorEnum.GUESTCUST_ERROR_SUCCESS)
80 elif seedfile:
81 # Found a seed dir
82 seed = os.path.join(self.paths.seed_dir, seedfile)
83@@ -198,6 +231,9 @@
84 else:
85 md['local-hostname'] = config.host_name
86
87+ if config.timezone:
88+ cfg['timezone'] = config.timezone
89+
90 return (md, ud, cfg)
91
92
93
94=== modified file 'cloudinit/sources/helpers/vmware/imc/config_nic.py'
95--- cloudinit/sources/helpers/vmware/imc/config_nic.py 2016-03-03 23:16:13 +0000
96+++ cloudinit/sources/helpers/vmware/imc/config_nic.py 2016-03-16 00:29:03 +0000
97@@ -205,7 +205,8 @@
98 def clear_dhcp(self):
99 logger.info('Clearing DHCP leases')
100
101- util.subp(["pkill", "dhclient"])
102+ # Ignore the return code 1.
103+ util.subp(["pkill", "dhclient"], rcs=[0, 1])
104 util.subp(["rm", "-f", "/var/lib/dhcp/*"])
105
106 def if_down_up(self):
107
108=== added file 'cloudinit/sources/helpers/vmware/imc/guestcust_error.py'
109--- cloudinit/sources/helpers/vmware/imc/guestcust_error.py 1970-01-01 00:00:00 +0000
110+++ cloudinit/sources/helpers/vmware/imc/guestcust_error.py 2016-03-16 00:29:03 +0000
111@@ -0,0 +1,24 @@
112+# vi: ts=4 expandtab
113+#
114+# Copyright (C) 2016 Canonical Ltd.
115+# Copyright (C) 2016 VMware Inc.
116+#
117+# Author: Sankar Tanguturi <stanguturi@vmware.com>
118+#
119+# This program is free software: you can redistribute it and/or modify
120+# it under the terms of the GNU General Public License version 3, as
121+# published by the Free Software Foundation.
122+#
123+# This program is distributed in the hope that it will be useful,
124+# but WITHOUT ANY WARRANTY; without even the implied warranty of
125+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
126+# GNU General Public License for more details.
127+#
128+# You should have received a copy of the GNU General Public License
129+# along with this program. If not, see <http://www.gnu.org/licenses/>.
130+
131+
132+class GuestCustErrorEnum:
133+ """Specifies different errors of Guest Customization engine"""
134+
135+ GUESTCUST_ERROR_SUCCESS = 0
136
137=== added file 'cloudinit/sources/helpers/vmware/imc/guestcust_event.py'
138--- cloudinit/sources/helpers/vmware/imc/guestcust_event.py 1970-01-01 00:00:00 +0000
139+++ cloudinit/sources/helpers/vmware/imc/guestcust_event.py 2016-03-16 00:29:03 +0000
140@@ -0,0 +1,27 @@
141+# vi: ts=4 expandtab
142+#
143+# Copyright (C) 2016 Canonical Ltd.
144+# Copyright (C) 2016 VMware Inc.
145+#
146+# Author: Sankar Tanguturi <stanguturi@vmware.com>
147+#
148+# This program is free software: you can redistribute it and/or modify
149+# it under the terms of the GNU General Public License version 3, as
150+# published by the Free Software Foundation.
151+#
152+# This program is distributed in the hope that it will be useful,
153+# but WITHOUT ANY WARRANTY; without even the implied warranty of
154+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
155+# GNU General Public License for more details.
156+#
157+# You should have received a copy of the GNU General Public License
158+# along with this program. If not, see <http://www.gnu.org/licenses/>.
159+
160+
161+class GuestCustEventEnum:
162+ """Specifies different types of Guest Customization Events"""
163+
164+ GUESTCUST_EVENT_CUSTOMIZE_FAILED = 100
165+ GUESTCUST_EVENT_NETWORK_SETUP_FAILED = 101
166+ GUESTCUST_EVENT_ENABLE_NICS = 103
167+ GUESTCUST_EVENT_QUERY_NICS = 104
168
169=== added file 'cloudinit/sources/helpers/vmware/imc/guestcust_state.py'
170--- cloudinit/sources/helpers/vmware/imc/guestcust_state.py 1970-01-01 00:00:00 +0000
171+++ cloudinit/sources/helpers/vmware/imc/guestcust_state.py 2016-03-16 00:29:03 +0000
172@@ -0,0 +1,25 @@
173+# vi: ts=4 expandtab
174+#
175+# Copyright (C) 2016 Canonical Ltd.
176+# Copyright (C) 2016 VMware Inc.
177+#
178+# Author: Sankar Tanguturi <stanguturi@vmware.com>
179+#
180+# This program is free software: you can redistribute it and/or modify
181+# it under the terms of the GNU General Public License version 3, as
182+# published by the Free Software Foundation.
183+#
184+# This program is distributed in the hope that it will be useful,
185+# but WITHOUT ANY WARRANTY; without even the implied warranty of
186+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
187+# GNU General Public License for more details.
188+#
189+# You should have received a copy of the GNU General Public License
190+# along with this program. If not, see <http://www.gnu.org/licenses/>.
191+
192+
193+class GuestCustStateEnum:
194+ """Specifies different states of Guest Customization engine"""
195+
196+ GUESTCUST_STATE_RUNNING = 4
197+ GUESTCUST_STATE_DONE = 5
198
199=== added file 'cloudinit/sources/helpers/vmware/imc/guestcust_util.py'
200--- cloudinit/sources/helpers/vmware/imc/guestcust_util.py 1970-01-01 00:00:00 +0000
201+++ cloudinit/sources/helpers/vmware/imc/guestcust_util.py 2016-03-16 00:29:03 +0000
202@@ -0,0 +1,128 @@
203+# vi: ts=4 expandtab
204+#
205+# Copyright (C) 2016 Canonical Ltd.
206+# Copyright (C) 2016 VMware Inc.
207+#
208+# Author: Sankar Tanguturi <stanguturi@vmware.com>
209+#
210+# This program is free software: you can redistribute it and/or modify
211+# it under the terms of the GNU General Public License version 3, as
212+# published by the Free Software Foundation.
213+#
214+# This program is distributed in the hope that it will be useful,
215+# but WITHOUT ANY WARRANTY; without even the implied warranty of
216+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
217+# GNU General Public License for more details.
218+#
219+# You should have received a copy of the GNU General Public License
220+# along with this program. If not, see <http://www.gnu.org/licenses/>.
221+
222+import logging
223+import os
224+import time
225+
226+from cloudinit import util
227+
228+from .guestcust_state import GuestCustStateEnum
229+from .guestcust_event import GuestCustEventEnum
230+
231+logger = logging.getLogger(__name__)
232+
233+
234+CLOUDINIT_LOG_FILE = "/var/log/cloud-init.log"
235+QUERY_NICS_SUPPORTED = "queryNicsSupported"
236+NICS_STATUS_CONNECTED = "connected"
237+
238+
239+# This will send a RPC command to the underlying
240+# VMware Virtualization Platform.
241+def send_rpc(rpc):
242+ if not rpc:
243+ return None
244+
245+ out = ""
246+ err = "Error sending the RPC command"
247+
248+ try:
249+ logger.debug("Sending RPC command: %s", rpc)
250+ (out, err) = util.subp(["vmware-rpctool", rpc], rcs=[0])
251+ # Remove the trailing newline in the output.
252+ if out:
253+ out = out.rstrip()
254+ except Exception as e:
255+ logger.debug("Failed to send RPC command")
256+ logger.exception(e)
257+
258+ return (out, err)
259+
260+
261+# This will send the customization status to the
262+# underlying VMware Virtualization Platform.
263+def set_customization_status(custstate, custerror, errormessage=None):
264+ message = ""
265+
266+ if errormessage:
267+ message = CLOUDINIT_LOG_FILE + "@" + errormessage
268+ else:
269+ message = CLOUDINIT_LOG_FILE
270+
271+ rpc = "deployPkg.update.state %d %d %s" % (custstate, custerror, message)
272+ (out, err) = send_rpc(rpc)
273+ return (out, err)
274+
275+
276+# This will read the file nics.txt in the specified directory
277+# and return the content
278+def get_nics_to_enable(dirpath):
279+ if not dirpath:
280+ return None
281+
282+ NICS_SIZE = 1024
283+ nicsfilepath = os.path.join(dirpath, "nics.txt")
284+ if not os.path.exists(nicsfilepath):
285+ return None
286+
287+ with open(nicsfilepath, 'r') as fp:
288+ nics = fp.read(NICS_SIZE)
289+
290+ return nics
291+
292+
293+# This will send a RPC command to the underlying VMware Virtualization platform
294+# and enable nics.
295+def enable_nics(nics):
296+ if not nics:
297+ logger.warning("No Nics found")
298+ return
299+
300+ enableNicsWaitRetries = 5
301+ enableNicsWaitCount = 5
302+ enableNicsWaitSeconds = 1
303+
304+ for attempt in range(0, enableNicsWaitRetries):
305+ logger.debug("Trying to connect interfaces, attempt %d", attempt)
306+ (out, err) = set_customization_status(
307+ GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
308+ GuestCustEventEnum.GUESTCUST_EVENT_ENABLE_NICS,
309+ nics)
310+ if not out:
311+ time.sleep(enableNicsWaitCount * enableNicsWaitSeconds)
312+ continue
313+
314+ if out != QUERY_NICS_SUPPORTED:
315+ logger.warning("NICS connection status query is not supported")
316+ return
317+
318+ for count in range(0, enableNicsWaitCount):
319+ (out, err) = set_customization_status(
320+ GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
321+ GuestCustEventEnum.GUESTCUST_EVENT_QUERY_NICS,
322+ nics)
323+ if out and out == NICS_STATUS_CONNECTED:
324+ logger.info("NICS are connected on %d second", count)
325+ return
326+
327+ time.sleep(enableNicsWaitSeconds)
328+
329+ logger.warning("Can't connect network interfaces after %d attempts",
330+ enableNicsWaitRetries)