diff --git a/cloudbaseinit/init.py b/cloudbaseinit/init.py index 43c7627e..c4b5385c 100644 --- a/cloudbaseinit/init.py +++ b/cloudbaseinit/init.py @@ -48,7 +48,7 @@ class InitManager(object): osutils.set_config_value(plugin_name, status, self._PLUGINS_CONFIG_SECTION) - def _exec_plugin(self, osutils, service, plugin): + def _exec_plugin(self, osutils, service, plugin, shared_data): plugin_name = plugin.get_name() status = self._get_plugin_status(osutils, plugin_name) @@ -59,7 +59,8 @@ class InitManager(object): LOG.info('Executing plugin \'%(plugin_name)s\'' % locals()) try: - (status, reboot_required) = plugin.execute(service) + (status, reboot_required) = plugin.execute(service, + shared_data) self._set_plugin_status(osutils, plugin_name, status) return reboot_required except Exception, ex: @@ -98,11 +99,14 @@ class InitManager(object): plugins = plugins_factory.PluginFactory().load_plugins() + plugins_shared_data = {} + reboot_required = False try: for plugin in plugins: if self._check_plugin_os_requirements(osutils, plugin): - if self._exec_plugin(osutils, service, plugin): + if self._exec_plugin(osutils, service, plugin, + plugins_shared_data): reboot_required = True if CONF.allow_reboot: break diff --git a/cloudbaseinit/plugins/base.py b/cloudbaseinit/plugins/base.py index 5a3dd7c0..d027c8fe 100644 --- a/cloudbaseinit/plugins/base.py +++ b/cloudbaseinit/plugins/base.py @@ -25,5 +25,5 @@ class BasePlugin(object): def get_os_requirements(self): return (None, None) - def execute(self, service): + def execute(self, service, shared_data): pass diff --git a/cloudbaseinit/plugins/constants.py b/cloudbaseinit/plugins/constants.py new file mode 100644 index 00000000..66ec8cfb --- /dev/null +++ b/cloudbaseinit/plugins/constants.py @@ -0,0 +1,18 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Cloudbase Solutions Srl +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +SHARED_DATA_USERNAME = "admin_user" +SHARED_DATA_PASSWORD = "admin_password" diff --git a/cloudbaseinit/plugins/factory.py b/cloudbaseinit/plugins/factory.py index fb88d73e..019d9a33 100644 --- a/cloudbaseinit/plugins/factory.py +++ b/cloudbaseinit/plugins/factory.py @@ -21,16 +21,19 @@ opts = [ cfg.ListOpt( 'plugins', default=[ - 'cloudbaseinit.plugins.windows.sethostname.SetHostNamePlugin', - 'cloudbaseinit.plugins.windows.createuser.CreateUserPlugin', - 'cloudbaseinit.plugins.windows.networkconfig.NetworkConfigPlugin', - 'cloudbaseinit.plugins.windows.sshpublickeys.' - 'SetUserSSHPublicKeysPlugin', - 'cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin', - 'cloudbaseinit.plugins.windows.userdata.UserDataPlugin', - 'cloudbaseinit.plugins.windows.setuserpassword.SetUserPasswordPlugin', - 'cloudbaseinit.plugins.windows.winrmlistener.' - 'ConfigWinRMListenerPlugin', + 'cloudbaseinit.plugins.windows.sethostname.SetHostNamePlugin', + 'cloudbaseinit.plugins.windows.createuser.CreateUserPlugin', + 'cloudbaseinit.plugins.windows.networkconfig.NetworkConfigPlugin', + 'cloudbaseinit.plugins.windows.sshpublickeys.' + 'SetUserSSHPublicKeysPlugin', + 'cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin', + 'cloudbaseinit.plugins.windows.userdata.UserDataPlugin', + 'cloudbaseinit.plugins.windows.setuserpassword.' + 'SetUserPasswordPlugin', + 'cloudbaseinit.plugins.windows.winrmlistener.' + 'ConfigWinRMListenerPlugin', + 'cloudbaseinit.plugins.windows.winrmcertificateauth.' + 'ConfigWinRMCertificateAuthPlugin', ], help='List of enabled plugin classes, ' 'to executed in the provided order'), diff --git a/cloudbaseinit/plugins/windows/createuser.py b/cloudbaseinit/plugins/windows/createuser.py index 9d1bc888..e03cba29 100644 --- a/cloudbaseinit/plugins/windows/createuser.py +++ b/cloudbaseinit/plugins/windows/createuser.py @@ -18,6 +18,7 @@ from cloudbaseinit.openstack.common import cfg from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.osutils import factory as osutils_factory from cloudbaseinit.plugins import base +from cloudbaseinit.plugins import constants opts = [ cfg.StrOpt('username', default='Admin', help='User to be added to the ' @@ -39,8 +40,9 @@ class CreateUserPlugin(base.BasePlugin): # by SetUserPasswordPlugin (starting from Grizzly) return osutils.generate_random_password(14) - def execute(self, service): + def execute(self, service, shared_data): user_name = CONF.username + shared_data[constants.SHARED_DATA_USERNAME] = user_name osutils = osutils_factory.OSUtilsFactory().get_os_utils() password = self._get_password(osutils) @@ -58,6 +60,9 @@ class CreateUserPlugin(base.BasePlugin): True) osutils.close_user_logon_session(token) + # TODO(alexpilotti): encrypt with DPAPI + shared_data[constants.SHARED_DATA_PASSWORD] = password + for group_name in CONF.groups: try: osutils.add_user_to_local_group(user_name, group_name) diff --git a/cloudbaseinit/plugins/windows/extendvolumes.py b/cloudbaseinit/plugins/windows/extendvolumes.py index ec3875e0..f82de176 100644 --- a/cloudbaseinit/plugins/windows/extendvolumes.py +++ b/cloudbaseinit/plugins/windows/extendvolumes.py @@ -156,7 +156,7 @@ class ExtendVolumesPlugin(base.BasePlugin): if CONF.volumes_to_extend is not None: return map(int, CONF.volumes_to_extend) - def execute(self, service): + def execute(self, service, shared_data): svc = vds.load_vds_service() providers = self._query_providers(svc) diff --git a/cloudbaseinit/plugins/windows/networkconfig.py b/cloudbaseinit/plugins/windows/networkconfig.py index 2f120970..7849b0f0 100644 --- a/cloudbaseinit/plugins/windows/networkconfig.py +++ b/cloudbaseinit/plugins/windows/networkconfig.py @@ -34,7 +34,7 @@ CONF.register_opts(opts) class NetworkConfigPlugin(base.BasePlugin): - def execute(self, service): + def execute(self, service, shared_data): meta_data = service.get_meta_data('openstack') if 'network_config' not in meta_data: return (base.PLUGIN_EXECUTION_DONE, False) diff --git a/cloudbaseinit/plugins/windows/sethostname.py b/cloudbaseinit/plugins/windows/sethostname.py index 3473d432..9c552693 100644 --- a/cloudbaseinit/plugins/windows/sethostname.py +++ b/cloudbaseinit/plugins/windows/sethostname.py @@ -22,7 +22,7 @@ LOG = logging.getLogger(__name__) class SetHostNamePlugin(base.BasePlugin): - def execute(self, service): + def execute(self, service, shared_data): meta_data = service.get_meta_data('openstack') if 'hostname' not in meta_data: LOG.debug('Hostname not found in metadata') diff --git a/cloudbaseinit/plugins/windows/setuserpassword.py b/cloudbaseinit/plugins/windows/setuserpassword.py index d1f4bd46..9ea34d7d 100644 --- a/cloudbaseinit/plugins/windows/setuserpassword.py +++ b/cloudbaseinit/plugins/windows/setuserpassword.py @@ -21,6 +21,7 @@ from cloudbaseinit.openstack.common import cfg from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.osutils import factory as osutils_factory from cloudbaseinit.plugins import base +from cloudbaseinit.plugins import constants from cloudbaseinit.utils import crypt opts = [ @@ -73,6 +74,9 @@ class SetUserPasswordPlugin(base.BasePlugin): LOG.warn('Using admin_pass metadata user password. Consider ' 'changing it as soon as possible') else: + # TODO(alexpilotti): setting a random password can be skipped + # if it's already present in the shared_data, as it has already + # been set by the CreateUserPlugin LOG.debug('Generating a random user password') # Generate a random password # Limit to 14 chars for compatibility with NT @@ -104,8 +108,11 @@ class SetUserPasswordPlugin(base.BasePlugin): osutils.set_user_password(user_name, password) return password - def execute(self, service): - user_name = CONF.username + def execute(self, service, shared_data): + # TODO(alexpilotti): The username selection logic must be set in the + # CreateUserPlugin instead if using CONF.username + user_name = shared_data.get(constants.SHARED_DATA_USERNAME, + CONF.username) if (service.can_post_password and service.is_password_set(self._post_password_md_ver)): @@ -114,6 +121,9 @@ class SetUserPasswordPlugin(base.BasePlugin): osutils = osutils_factory.OSUtilsFactory().get_os_utils() if osutils.user_exists(user_name): password = self._set_password(service, osutils, user_name) + # TODO(alexpilotti): encrypt with DPAPI + shared_data[constants.SHARED_DATA_PASSWORD] = password + if not service.can_post_password: LOG.info('Cannot set the password in the metadata as it ' 'is not supported by this service') diff --git a/cloudbaseinit/plugins/windows/sshpublickeys.py b/cloudbaseinit/plugins/windows/sshpublickeys.py index bff5d68d..1a17307d 100644 --- a/cloudbaseinit/plugins/windows/sshpublickeys.py +++ b/cloudbaseinit/plugins/windows/sshpublickeys.py @@ -26,7 +26,7 @@ LOG = logging.getLogger(__name__) class SetUserSSHPublicKeysPlugin(base.BasePlugin): - def execute(self, service): + def execute(self, service, shared_data): meta_data = service.get_meta_data('openstack') if not 'public_keys' in meta_data: return (base.PLUGIN_EXECUTION_DONE, False) diff --git a/cloudbaseinit/plugins/windows/userdata.py b/cloudbaseinit/plugins/windows/userdata.py index 8e318ae9..9ce4e952 100644 --- a/cloudbaseinit/plugins/windows/userdata.py +++ b/cloudbaseinit/plugins/windows/userdata.py @@ -50,7 +50,7 @@ class UserDataPlugin(base.BasePlugin): os.path.dirname(os.path.realpath(__file__))), "windows/userdata-plugins") - def execute(self, service): + def execute(self, service, shared_data): try: user_data = service.get_user_data('openstack') except metadata_services_base.NotExistingMetadataException: diff --git a/cloudbaseinit/plugins/windows/winrmlistener.py b/cloudbaseinit/plugins/windows/winrmlistener.py index 49eb6703..56eaa78a 100644 --- a/cloudbaseinit/plugins/windows/winrmlistener.py +++ b/cloudbaseinit/plugins/windows/winrmlistener.py @@ -36,7 +36,7 @@ LOG = logging.getLogger(__name__) class ConfigWinRMListenerPlugin(base.BasePlugin): - _cert_subject = "CN=Cloudbase-Init" + _cert_subject = "CN=Cloudbase-Init WinRM" _winrm_service_name = "WinRM" def _check_winrm_service(self, osutils): @@ -59,7 +59,7 @@ class ConfigWinRMListenerPlugin(base.BasePlugin): return True - def execute(self, service): + def execute(self, service, shared_data): osutils = osutils_factory.OSUtilsFactory().get_os_utils() if not self._check_winrm_service(osutils):