Pep8 and assorted cleanups on multi-part userdata

General cleanup and minor refactoring.
This commit is contained in:
Alessandro Pilotti 2013-08-13 02:56:04 +03:00
parent 3c8cd5b39f
commit 0a0b58f673
6 changed files with 124 additions and 141 deletions

View File

@ -14,21 +14,22 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
LOG = logging.getLogger("cloudbaseinit") LOG = logging.getLogger("cloudbaseinit")
def get_plugin(parent_set): def get_plugin(parent_set):
return CloudConfigHandler(parent_set) return CloudConfigHandler(parent_set)
class CloudConfigHandler: class CloudConfigHandler:
def __init__(self, parent_set): def __init__(self, parent_set):
LOG.info("Cloud-config part handler is loaded.") LOG.info("Cloud-config part handler is loaded.")
self.type = "text/cloud-config" self.type = "text/cloud-config"
self.name = "Cloud-config userdata plugin" self.name = "Cloud-config userdata plugin"
return
def process(self, part): def process(self, part):
return pass

View File

@ -15,33 +15,25 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import re
import tempfile
import uuid
import email
import tempfile
import os
import errno
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.osutils.factory import * from cloudbaseinit.plugins.windows import userdata
from cloudbaseinit.plugins.windows.userdata import handle
LOG = logging.getLogger("cloudbaseinit") LOG = logging.getLogger("cloudbaseinit")
def get_plugin(parent_set): def get_plugin(parent_set):
return HeatUserDataHandler(parent_set) return HeatUserDataHandler(parent_set)
class HeatUserDataHandler: class HeatUserDataHandler:
def __init__(self, parent_set): def __init__(self, parent_set):
LOG.info("Heat user data part handler is loaded.") LOG.info("Heat user data part handler is loaded.")
self.type = "text/x-cfninitdata" self.type = "text/x-cfninitdata"
self.name = "Heat userdata plugin" self.name = "Heat userdata plugin"
return
def process(self, part): def process(self, part):
#Only user-data part of Heat multipart data is supported. All other cfinitdata part will be skipped #Only user-data part of Heat multipart data is supported.
#All other cfinitdata part will be skipped
if part.get_filename() == "cfn-userdata": if part.get_filename() == "cfn-userdata":
handle(part.get_payload()) userdata.handle(part.get_payload())
return

View File

@ -14,19 +14,23 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import imp import imp
import os import os
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
LOG = logging.getLogger("cloudbaseinit") LOG = logging.getLogger("cloudbaseinit")
def get_plugin(parent_set): def get_plugin(parent_set):
return PartHandlerScriptHandler(parent_set) return PartHandlerScriptHandler(parent_set)
def load_from_file(filepath, function): def load_from_file(filepath, function):
class_inst = None class_inst = None
mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1]) mod_name, file_ext = os.path.splitext(os.path.split(filepath)[-1])
if file_ext.lower() == '.py': if file_ext.lower() == '.py':
py_mod = imp.load_source(mod_name, filepath) py_mod = imp.load_source(mod_name, filepath)
@ -35,33 +39,28 @@ def load_from_file(filepath, function):
py_mod = imp.load_compiled(mod_name, filepath) py_mod = imp.load_compiled(mod_name, filepath)
if hasattr(py_mod, function): if hasattr(py_mod, function):
callable = getattr(__import__(mod_name),function) return getattr(__import__(mod_name), function)
return callable
class PartHandlerScriptHandler: class PartHandlerScriptHandler:
def __init__(self, parent_set): def __init__(self, parent_set):
LOG.info("Part-handler script part handler is loaded.") LOG.info("Part-handler script part handler is loaded.")
self.type = "text/part-handler" self.type = "text/part-handler"
self.name = "Part-handler userdata plugin" self.name = "Part-handler userdata plugin"
self.parent_set = parent_set self.parent_set = parent_set
return
def process(self, part): def process(self, part):
handler_path = self.parent_set.path + "/part-handler/"+part.get_filename() handler_path = (self.parent_set.path + "/part-handler/" +
with open(handler_path, "wb") as f: part.get_filename())
with open(handler_path, "wb") as f:
f.write(part.get_payload()) f.write(part.get_payload())
list_types = load_from_file(handler_path, "list_types")
list_types = load_from_file(handler_path,"list_types") handle_part = load_from_file(handler_path, "handle_part")
handle_part = load_from_file(handler_path, "handle_part")
if list_types is not None and handle_part is not None:
if list_types is not None and handle_part is not None: parts = list_types()
parts = list_types() for part in parts:
for part in parts: LOG.info("Installing new custom handler for type: %s", part)
LOG.info("Installing new custom handler for type: %s", part) self.parent_set.custom_handlers[part] = handle_part
self.parent_set.custom_handlers[part] = handle_part self.parent_set.has_custom_handlers = True
self.parent_set.has_custom_handlers = True
return

View File

@ -15,36 +15,31 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import re
import tempfile
import uuid
import email
import tempfile
import os import os
import errno import tempfile
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.osutils.factory import * from cloudbaseinit.osutils import factory as osutils_factory
LOG = logging.getLogger("cloudbaseinit") LOG = logging.getLogger("cloudbaseinit")
def get_plugin(parent_set): def get_plugin(parent_set):
return ShellScriptHandler(parent_set) return ShellScriptHandler(parent_set)
class ShellScriptHandler: class ShellScriptHandler:
def __init__(self, parent_set): def __init__(self, parent_set):
LOG.info("Shell-script part handler is loaded.") LOG.info("Shell-script part handler is loaded.")
self.type = "text/x-shellscript" self.type = "text/x-shellscript"
self.name = "Shell-script userdata plugin" self.name = "Shell-script userdata plugin"
return
def process(self, part): def process(self, part):
osutils = OSUtilsFactory().get_os_utils() osutils = osutils_factory.OSUtilsFactory().get_os_utils()
file_name = part.get_filename() file_name = part.get_filename()
target_path = os.path.join(tempfile.gettempdir(), file_name) target_path = os.path.join(tempfile.gettempdir(), file_name)
if file_name.endswith(".cmd"): if file_name.endswith(".cmd"):
args = [target_path] args = [target_path]
shell = True shell = True
@ -54,7 +49,7 @@ class ShellScriptHandler:
elif file_name.endswith(".ps1"): elif file_name.endswith(".ps1"):
args = ['powershell.exe', '-ExecutionPolicy', 'RemoteSigned', args = ['powershell.exe', '-ExecutionPolicy', 'RemoteSigned',
'-NonInteractive', target_path] '-NonInteractive', target_path]
shell = False shell = False
else: else:
# Unsupported # Unsupported
LOG.warning('Unsupported shell format') LOG.warning('Unsupported shell format')
@ -69,10 +64,10 @@ class ShellScriptHandler:
LOG.debug('User_data stdout:\n%s' % out) LOG.debug('User_data stdout:\n%s' % out)
LOG.debug('User_data stderr:\n%s' % err) LOG.debug('User_data stderr:\n%s' % err)
except Exception, ex: except Exception, ex:
LOG.warning('An error occurred during user_data execution: \'%s\'' % ex) LOG.warning('An error occurred during user_data execution: \'%s\''
% ex)
finally: finally:
if os.path.exists(target_path): if os.path.exists(target_path):
os.remove(target_path) os.remove(target_path)
return False return False

View File

@ -14,26 +14,24 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import email
import os import os
import re import re
import tempfile import tempfile
import uuid import uuid
import email
import errno
from cloudbaseinit.metadata.services import base as metadata_services_base from cloudbaseinit.metadata.services import base as metadata_services_base
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.osutils import factory as osutils_factory from cloudbaseinit.osutils import factory as osutils_factory
from cloudbaseinit.plugins import base from cloudbaseinit.plugins import base
from cloudbaseinit.plugins.windows.userdata_plugins import PluginSet from cloudbaseinit.plugins.windows import userdata_plugins
from cloudbaseinit.openstack.common import cfg
opts = [ opts = [
cfg.StrOpt('user_data_folder', default='cloud-data', cfg.StrOpt('user_data_folder', default='cloud-data',
help='Specifies a folder to store multipart data files.'), help='Specifies a folder to store multipart data files.'),
] ]
CONF = cfg.CONF CONF = cfg.CONF
CONF.register_opts(opts) CONF.register_opts(opts)
@ -41,18 +39,17 @@ CONF.register_opts(opts)
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class UserDataPlugin(base.BasePlugin): class UserDataPlugin(base.BasePlugin):
def __init__(self, cfg=CONF): def __init__(self):
self.cfg = cfg
self.msg = None self.msg = None
self.plugin_set = PluginSet(self.get_plugin_path()) self.plugin_set = userdata_plugins.PluginSet(self._get_plugin_path())
self.plugin_set.reload() self.plugin_set.reload()
return
def get_plugin_path(self): def _get_plugin_path(self):
return os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), return os.path.join(os.path.dirname(
"windows/userdata-plugins") os.path.dirname(os.path.realpath(__file__))),
"windows/userdata-plugins")
def execute(self, service): def execute(self, service):
try: try:
user_data = service.get_user_data('openstack') user_data = service.get_user_data('openstack')
@ -62,70 +59,70 @@ class UserDataPlugin(base.BasePlugin):
if not user_data: if not user_data:
return (base.PLUGIN_EXECUTION_DONE, False) return (base.PLUGIN_EXECUTION_DONE, False)
self.process_userdata(user_data) self._process_userdata(user_data)
return (base.PLUGIN_EXECUTION_DONE, False) return (base.PLUGIN_EXECUTION_DONE, False)
def process_userdata(self, user_data): def _process_userdata(self, user_data):
LOG.debug('User data content:\n%s' % user_data) LOG.debug('User data content:\n%s' % user_data)
if user_data.startswith('Content-Type: multipart'): if user_data.startswith('Content-Type: multipart'):
for part in self.parse_MIME(user_data): for part in self._parse_mime(user_data):
self.process_part(part) self._process_part(part)
else: else:
handle(user_data) handle(user_data)
return
def _process_part(self, part):
def process_part(self, part): part_handler = self._get_part_handler(part)
part_handler = self.get_part_handler(part)
if part_handler is not None: if part_handler is not None:
try: try:
self.begin_part_process_event(part) self._begin_part_process_event(part)
LOG.info("Processing part %s filename: %s with handler: %s", part.get_content_type(), part.get_filename(), part_handler.name) LOG.info("Processing part %s filename: %s with handler: %s",
part.get_content_type(),
part.get_filename(),
part_handler.name)
part_handler.process(part) part_handler.process(part)
self.end_part_process_event(part) self._end_part_process_event(part)
except Exception,e: except Exception, e:
LOG.error('Exception during multipart part handling: %s %s \n %s' , part.get_content_type(), part.get_filename(), e) LOG.error('Exception during multipart part handling: '
return '%s %s \n %s', part.get_content_type(),
part.get_filename(), e)
def begin_part_process_event(self, part):
handler = self.get_custom_handler(part) def _begin_part_process_event(self, part):
handler = self._get_custom_handler(part)
if handler is not None: if handler is not None:
try: try:
handler("","__begin__", part.get_filename(), part.get_payload()) handler("", "__begin__", part.get_filename(),
except Exception,e: part.get_payload())
LOG.error("Exception occurred during custom handle script invocation (__begin__): %s ", e) except Exception, e:
return LOG.error("Exception occurred during custom handle script "
"invocation (__begin__): %s ", e)
def end_part_process_event(self, part):
handler = self.get_custom_handler(part) def _end_part_process_event(self, part):
handler = self._get_custom_handler(part)
if handler is not None: if handler is not None:
try: try:
handler("","__end__", part.get_filename(), part.get_payload()) handler("", "__end__", part.get_filename(), part.get_payload())
except Exception,e: except Exception, e:
LOG.error("Exception occurred during custom handle script invocation (__end__): %s ", e) LOG.error("Exception occurred during custom handle script "
return "invocation (__end__): %s ", e)
def _get_custom_handler(self, part):
def get_custom_handler(self, part):
if self.plugin_set.has_custom_handlers: if self.plugin_set.has_custom_handlers:
if part.get_content_type() in self.plugin_set.custom_handlers: if part.get_content_type() in self.plugin_set.custom_handlers:
handler = self.plugin_set.custom_handlers[part.get_content_type()] handler = self.plugin_set.custom_handlers[
part.get_content_type()]
return handler return handler
return None
def get_part_handler(self, part): def _get_part_handler(self, part):
if part.get_content_type() in self.plugin_set.set: if part.get_content_type() in self.plugin_set.set:
handler = self.plugin_set.set[part.get_content_type()] handler = self.plugin_set.set[part.get_content_type()]
return handler return handler
else:
return None def _parse_mime(self, user_data):
def parse_MIME(self, user_data):
self.msg = email.message_from_string(user_data) self.msg = email.message_from_string(user_data)
return self.msg.walk() return self.msg.walk()
def handle(user_data):
def handle(self, user_data):
osutils = osutils_factory.OSUtilsFactory().get_os_utils() osutils = osutils_factory.OSUtilsFactory().get_os_utils()
target_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4())) target_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4()))
@ -178,4 +175,3 @@ def handle(self, user_data):
os.remove(target_path) os.remove(target_path)
return (base.PLUGIN_EXECUTION_DONE, False) return (base.PLUGIN_EXECUTION_DONE, False)

View File

@ -15,14 +15,16 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import glob
import imp import imp
import os import os
import sys, glob import sys
from cloudbaseinit.openstack.common import log as logging
import traceback import traceback
from cloudbaseinit.openstack.common import log as logging
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
global builders
def load_from_file(filepath, parent_set): def load_from_file(filepath, parent_set):
class_inst = None class_inst = None
@ -36,8 +38,8 @@ def load_from_file(filepath, parent_set):
py_mod = imp.load_compiled(mod_name, filepath) py_mod = imp.load_compiled(mod_name, filepath)
if hasattr(py_mod, "get_plugin"): if hasattr(py_mod, "get_plugin"):
callable = getattr(__import__(mod_name), "get_plugin") clb = getattr(__import__(mod_name), "get_plugin")
class_inst = callable(parent_set) class_inst = clb(parent_set)
return class_inst return class_inst
@ -45,37 +47,35 @@ def load_from_file(filepath, parent_set):
class PluginSet: class PluginSet:
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
sys.path.append(self.path) sys.path.append(self.path)
self.set = {} self.set = {}
self.has_custom_handlers = False self.has_custom_handlers = False
self.custom_handlers = {} self.custom_handlers = {}
def get_plugin(self, content_type, file_name): def get_plugin(self, content_type, file_name):
return pass
def load(self): def load(self):
files = glob.glob(self.path + '/*.py') files = glob.glob(self.path + '/*.py')
if len(files) == 0: if len(files) == 0:
LOG.debug("No user data plug-ins found in %s:", self.path) LOG.debug("No user data plug-ins found in %s:", self.path)
return return
for file in files: for f in files:
LOG.debug("Trying to load user data plug-in from file: %s", file) LOG.debug("Trying to load user data plug-in from file: %s", f)
try: try:
plugin = load_from_file(file, self) plugin = load_from_file(f, self)
if plugin is not None: if plugin is not None:
LOG.info("Plugin '%s' loaded.", plugin.name) LOG.info("Plugin '%s' loaded.", plugin.name)
self.set[plugin.type] = plugin self.set[plugin.type] = plugin
except: except:
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
LOG.error('Can`t load plugin from the file %s. Skip it.', file) LOG.error('Can`t load plugin from the file %s. Skip it.', f)
LOG.debug(repr(traceback.format_exception(exc_type, exc_value, LOG.debug(repr(traceback.format_exception(exc_type, exc_value,
exc_traceback))) exc_traceback)))
def reload(self): def reload(self):
self.set = {} self.set = {}
self.load() self.load()