diff options
author | Maitreyee Saikia <msaikia@vmware.com> | 2017-08-15 09:33:50 -0600 |
---|---|---|
committer | Chad Smith <chad.smith@canonical.com> | 2017-08-15 09:33:50 -0600 |
commit | 1f8183ff4750cc7f8798749987ef10912719544d (patch) | |
tree | 34bb4eb37c3a358a617181476f0a670681f1af8b /cloudinit/sources | |
parent | d5f855dd96ccbea77f61b0515b574ad2c43d116d (diff) | |
download | vyos-cloud-init-1f8183ff4750cc7f8798749987ef10912719544d.tar.gz vyos-cloud-init-1f8183ff4750cc7f8798749987ef10912719544d.zip |
vcloud directory: Guest Customization support for passwords
This feature enables the following VMware VCloud Director functionality:
1. Setting admin password
2. Expire password.
3. Set admin password and expire.
Password configuration is triggered only as part of a full
recustomization, that happens either on first power on or when
"poweron and full recustomization" is selected. Full customization
flow is determined by marker files. Unique marker ids are
generated when full recustomization is requested. And marker file based
on these marker ids help to determine if we need to execute the above
configuration.
Diffstat (limited to 'cloudinit/sources')
-rw-r--r-- | cloudinit/sources/DataSourceOVF.py | 63 | ||||
-rw-r--r-- | cloudinit/sources/helpers/vmware/imc/config.py | 24 | ||||
-rw-r--r-- | cloudinit/sources/helpers/vmware/imc/config_passwd.py | 67 |
3 files changed, 150 insertions, 4 deletions
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py index f20c9a65..73d38771 100644 --- a/cloudinit/sources/DataSourceOVF.py +++ b/cloudinit/sources/DataSourceOVF.py @@ -25,6 +25,8 @@ from cloudinit.sources.helpers.vmware.imc.config_file \ import ConfigFile from cloudinit.sources.helpers.vmware.imc.config_nic \ import NicConfigurator +from cloudinit.sources.helpers.vmware.imc.config_passwd \ + import PasswordConfigurator from cloudinit.sources.helpers.vmware.imc.guestcust_error \ import GuestCustErrorEnum from cloudinit.sources.helpers.vmware.imc.guestcust_event \ @@ -117,6 +119,8 @@ class DataSourceOVF(sources.DataSource): (md, ud, cfg) = read_vmware_imc(conf) dirpath = os.path.dirname(vmwareImcConfigFilePath) nics = get_nics_to_enable(dirpath) + markerid = conf.marker_id + markerexists = check_marker_exists(markerid) except Exception as e: LOG.debug("Error parsing the customization Config File") LOG.exception(e) @@ -127,7 +131,6 @@ class DataSourceOVF(sources.DataSource): return False finally: util.del_dir(os.path.dirname(vmwareImcConfigFilePath)) - try: LOG.debug("Applying the Network customization") nicConfigurator = NicConfigurator(conf.nics) @@ -140,6 +143,35 @@ class DataSourceOVF(sources.DataSource): GuestCustEventEnum.GUESTCUST_EVENT_NETWORK_SETUP_FAILED) enable_nics(nics) return False + if markerid and not markerexists: + LOG.debug("Applying password customization") + pwdConfigurator = PasswordConfigurator() + adminpwd = conf.admin_password + try: + resetpwd = conf.reset_password + if adminpwd or resetpwd: + pwdConfigurator.configure(adminpwd, resetpwd, + self.distro) + else: + LOG.debug("Changing password is not needed") + except Exception as e: + LOG.debug("Error applying Password Configuration: %s", e) + set_customization_status( + GuestCustStateEnum.GUESTCUST_STATE_RUNNING, + GuestCustEventEnum.GUESTCUST_EVENT_CUSTOMIZE_FAILED) + enable_nics(nics) + return False + if markerid: + LOG.debug("Handle marker creation") + try: + setup_marker_files(markerid) + except Exception as e: + LOG.debug("Error creating marker files: %s", e) + set_customization_status( + GuestCustStateEnum.GUESTCUST_STATE_RUNNING, + GuestCustEventEnum.GUESTCUST_EVENT_CUSTOMIZE_FAILED) + enable_nics(nics) + return False vmwarePlatformFound = True set_customization_status( @@ -445,4 +477,33 @@ datasources = ( def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# To check if marker file exists +def check_marker_exists(markerid): + """ + Check the existence of a marker file. + Presence of marker file determines whether a certain code path is to be + executed. It is needed for partial guest customization in VMware. + """ + if not markerid: + return False + markerfile = "/.markerfile-" + markerid + if os.path.exists(markerfile): + return True + return False + + +# Create a marker file +def setup_marker_files(markerid): + """ + Create a new marker file. + Marker files are unique to a full customization workflow in VMware + environment. + """ + if not markerid: + return + markerfile = "/.markerfile-" + markerid + util.del_file("/.markerfile-*.txt") + open(markerfile, 'w').close() + # vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/config.py b/cloudinit/sources/helpers/vmware/imc/config.py index 9a5e3a8a..49d441db 100644 --- a/cloudinit/sources/helpers/vmware/imc/config.py +++ b/cloudinit/sources/helpers/vmware/imc/config.py @@ -5,6 +5,7 @@ # # This file is part of cloud-init. See LICENSE file for license information. + from .nic import Nic @@ -14,13 +15,16 @@ class Config(object): Specification file. """ + CUSTOM_SCRIPT = 'CUSTOM-SCRIPT|SCRIPT-NAME' DNS = 'DNS|NAMESERVER|' - SUFFIX = 'DNS|SUFFIX|' + DOMAINNAME = 'NETWORK|DOMAINNAME' + HOSTNAME = 'NETWORK|HOSTNAME' + MARKERID = 'MISC|MARKER-ID' PASS = 'PASSWORD|-PASS' + RESETPASS = 'PASSWORD|RESET' + SUFFIX = 'DNS|SUFFIX|' TIMEZONE = 'DATETIME|TIMEZONE' UTC = 'DATETIME|UTC' - HOSTNAME = 'NETWORK|HOSTNAME' - DOMAINNAME = 'NETWORK|DOMAINNAME' def __init__(self, configFile): self._configFile = configFile @@ -82,4 +86,18 @@ class Config(object): return res + @property + def reset_password(self): + """Retreives if the root password needs to be reset.""" + resetPass = self._configFile.get(Config.RESETPASS, 'no') + resetPass = resetPass.lower() + if resetPass not in ('yes', 'no'): + raise ValueError('ResetPassword value should be yes/no') + return resetPass == 'yes' + + @property + def marker_id(self): + """Returns marker id.""" + return self._configFile.get(Config.MARKERID, None) + # vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/config_passwd.py b/cloudinit/sources/helpers/vmware/imc/config_passwd.py new file mode 100644 index 00000000..75cfbaaf --- /dev/null +++ b/cloudinit/sources/helpers/vmware/imc/config_passwd.py @@ -0,0 +1,67 @@ +# Copyright (C) 2016 Canonical Ltd. +# Copyright (C) 2016 VMware INC. +# +# Author: Maitreyee Saikia <msaikia@vmware.com> +# +# This file is part of cloud-init. See LICENSE file for license information. + + +import logging +import os + +from cloudinit import util + +LOG = logging.getLogger(__name__) + + +class PasswordConfigurator(object): + """ + Class for changing configurations related to passwords in a VM. Includes + setting and expiring passwords. + """ + def configure(self, passwd, resetPasswd, distro): + """ + Main method to perform all functionalities based on configuration file + inputs. + @param passwd: encoded admin password. + @param resetPasswd: boolean to determine if password needs to be reset. + @return cfg: dict to be used by cloud-init set_passwd code. + """ + LOG.info('Starting password configuration') + if passwd: + passwd = util.b64d(passwd) + allRootUsers = [] + for line in open('/etc/passwd', 'r'): + if line.split(':')[2] == '0': + allRootUsers.append(line.split(':')[0]) + # read shadow file and check for each user, if its uid0 or root. + uidUsersList = [] + for line in open('/etc/shadow', 'r'): + user = line.split(':')[0] + if user in allRootUsers: + uidUsersList.append(user) + if passwd: + LOG.info('Setting admin password') + distro.set_passwd('root', passwd) + if resetPasswd: + self.reset_password(uidUsersList) + LOG.info('Configure Password completed!') + + def reset_password(self, uidUserList): + """ + Method to reset password. Use passwd --expire command. Use chage if + not succeeded using passwd command. Log failure message otherwise. + @param: list of users for which to expire password. + """ + LOG.info('Expiring password.') + for user in uidUserList: + try: + out, err = util.subp(['passwd', '--expire', user]) + except util.ProcessExecutionError as e: + if os.path.exists('/usr/bin/chage'): + out, e = util.subp(['chage', '-d', '0', user]) + else: + LOG.warning('Failed to expire password for %s with error: ' + '%s', user, e) + +# vi: ts=4 expandtab |