Normalize line endings

This commit is contained in:
Alessandro Pilotti 2014-02-09 21:41:45 +02:00
parent 9ef84f6bd8
commit b4b3f6bb4e
9 changed files with 843 additions and 841 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Always use LF
* text=lf

View File

@ -1,122 +1,122 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import sys
from cloudbaseinit.metadata import factory as metadata_factory
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 as plugins_base
from cloudbaseinit.plugins import factory as plugins_factory
opts = [
cfg.BoolOpt('allow_reboot', default=True, help='Allows OS reboots '
'requested by plugins'),
cfg.BoolOpt('stop_service_on_exit', default=True, help='In case of '
'execution as a service, specifies if the service '
'must be gracefully stopped before exiting'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class InitManager(object):
_PLUGINS_CONFIG_SECTION = 'Plugins'
def _get_plugin_status(self, osutils, plugin_name):
return osutils.get_config_value(plugin_name,
self._PLUGINS_CONFIG_SECTION)
def _set_plugin_status(self, osutils, plugin_name, status):
osutils.set_config_value(plugin_name, status,
self._PLUGINS_CONFIG_SECTION)
def _exec_plugin(self, osutils, service, plugin, shared_data):
plugin_name = plugin.get_name()
status = self._get_plugin_status(osutils, plugin_name)
if status == plugins_base.PLUGIN_EXECUTION_DONE:
LOG.debug('Plugin \'%(plugin_name)s\' execution already done, '
'skipping' % locals())
else:
LOG.info('Executing plugin \'%(plugin_name)s\'' %
locals())
try:
(status, reboot_required) = plugin.execute(service,
shared_data)
self._set_plugin_status(osutils, plugin_name, status)
return reboot_required
except Exception, ex:
LOG.error('plugin \'%(plugin_name)s\' failed '
'with error \'%(ex)s\'' % locals())
LOG.exception(ex)
def _check_plugin_os_requirements(self, osutils, plugin):
supported = False
plugin_name = plugin.get_name()
(required_platform, min_os_version) = plugin.get_os_requirements()
if required_platform and sys.platform != required_platform:
LOG.debug('Skipping plugin: \'%s\'. Platform not supported' %
plugin_name)
else:
if not min_os_version:
supported = True
else:
os_major, os_minor = min_os_version
if osutils.check_os_version(os_major, os_minor):
supported = True
else:
LOG.debug('Skipping plugin: \'%s\'. OS version not '
'supported' % plugin_name)
return supported
def configure_host(self):
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
osutils.wait_for_boot_completion()
mdsf = metadata_factory.MetadataServiceFactory()
service = mdsf.get_metadata_service()
LOG.info('Metadata service loaded: \'%s\'' %
service.get_name())
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,
plugins_shared_data):
reboot_required = True
if CONF.allow_reboot:
break
finally:
service.cleanup()
if reboot_required and CONF.allow_reboot:
try:
osutils.reboot()
except Exception, ex:
LOG.error('reboot failed with error \'%s\'' % ex)
elif CONF.stop_service_on_exit:
osutils.terminate()
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import sys
from cloudbaseinit.metadata import factory as metadata_factory
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 as plugins_base
from cloudbaseinit.plugins import factory as plugins_factory
opts = [
cfg.BoolOpt('allow_reboot', default=True, help='Allows OS reboots '
'requested by plugins'),
cfg.BoolOpt('stop_service_on_exit', default=True, help='In case of '
'execution as a service, specifies if the service '
'must be gracefully stopped before exiting'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class InitManager(object):
_PLUGINS_CONFIG_SECTION = 'Plugins'
def _get_plugin_status(self, osutils, plugin_name):
return osutils.get_config_value(plugin_name,
self._PLUGINS_CONFIG_SECTION)
def _set_plugin_status(self, osutils, plugin_name, status):
osutils.set_config_value(plugin_name, status,
self._PLUGINS_CONFIG_SECTION)
def _exec_plugin(self, osutils, service, plugin, shared_data):
plugin_name = plugin.get_name()
status = self._get_plugin_status(osutils, plugin_name)
if status == plugins_base.PLUGIN_EXECUTION_DONE:
LOG.debug('Plugin \'%(plugin_name)s\' execution already done, '
'skipping' % locals())
else:
LOG.info('Executing plugin \'%(plugin_name)s\'' %
locals())
try:
(status, reboot_required) = plugin.execute(service,
shared_data)
self._set_plugin_status(osutils, plugin_name, status)
return reboot_required
except Exception, ex:
LOG.error('plugin \'%(plugin_name)s\' failed '
'with error \'%(ex)s\'' % locals())
LOG.exception(ex)
def _check_plugin_os_requirements(self, osutils, plugin):
supported = False
plugin_name = plugin.get_name()
(required_platform, min_os_version) = plugin.get_os_requirements()
if required_platform and sys.platform != required_platform:
LOG.debug('Skipping plugin: \'%s\'. Platform not supported' %
plugin_name)
else:
if not min_os_version:
supported = True
else:
os_major, os_minor = min_os_version
if osutils.check_os_version(os_major, os_minor):
supported = True
else:
LOG.debug('Skipping plugin: \'%s\'. OS version not '
'supported' % plugin_name)
return supported
def configure_host(self):
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
osutils.wait_for_boot_completion()
mdsf = metadata_factory.MetadataServiceFactory()
service = mdsf.get_metadata_service()
LOG.info('Metadata service loaded: \'%s\'' %
service.get_name())
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,
plugins_shared_data):
reboot_required = True
if CONF.allow_reboot:
break
finally:
service.cleanup()
if reboot_required and CONF.allow_reboot:
try:
osutils.reboot()
except Exception, ex:
LOG.error('reboot failed with error \'%s\'' % ex)
elif CONF.stop_service_on_exit:
osutils.terminate()

View File

@ -1,52 +1,52 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.utils import classloader
opts = [
cfg.ListOpt('metadata_services',
default=[
'cloudbaseinit.metadata.services.httpservice.HttpService',
'cloudbaseinit.metadata.services.configdrive.configdrive.'
'ConfigDriveService',
'cloudbaseinit.metadata.services.ec2service.EC2Service'
],
help='List of enabled metadata service classes, '
'to be tested fro availability in the provided order. '
'The first available service will be used to retrieve '
'metadata')
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class MetadataServiceFactory(object):
def get_metadata_service(self):
# Return the first service that loads correctly
cl = classloader.ClassLoader()
for class_path in CONF.metadata_services:
service = cl.load_class(class_path)()
try:
if service.load():
return service
except Exception, ex:
LOG.error('Failed to load metadata service \'%(class_path)s\'')
LOG.exception(ex)
raise Exception("No available service found")
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.utils import classloader
opts = [
cfg.ListOpt('metadata_services',
default=[
'cloudbaseinit.metadata.services.httpservice.HttpService',
'cloudbaseinit.metadata.services.configdrive.configdrive.'
'ConfigDriveService',
'cloudbaseinit.metadata.services.ec2service.EC2Service'
],
help='List of enabled metadata service classes, '
'to be tested fro availability in the provided order. '
'The first available service will be used to retrieve '
'metadata')
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class MetadataServiceFactory(object):
def get_metadata_service(self):
# Return the first service that loads correctly
cl = classloader.ClassLoader()
for class_path in CONF.metadata_services:
service = cl.load_class(class_path)()
try:
if service.load():
return service
except Exception, ex:
LOG.error('Failed to load metadata service \'%(class_path)s\'')
LOG.exception(ex)
raise Exception("No available service found")

View File

@ -1,145 +1,145 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import ctypes
from ctypes import windll
from ctypes import wintypes
kernel32 = windll.kernel32
# VirtDisk.dll is available starting from Windows Server 2008 R2 / Windows7
virtdisk = None
class Win32_GUID(ctypes.Structure):
_fields_ = [("Data1", wintypes.DWORD),
("Data2", wintypes.WORD),
("Data3", wintypes.WORD),
("Data4", wintypes.BYTE * 8)]
def get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT():
guid = Win32_GUID()
guid.Data1 = 0xec984aec
guid.Data2 = 0xa0f9
guid.Data3 = 0x47e9
ByteArray8 = wintypes.BYTE * 8
guid.Data4 = ByteArray8(0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b)
return guid
class Win32_VIRTUAL_STORAGE_TYPE(ctypes.Structure):
_fields_ = [
('DeviceId', wintypes.DWORD),
('VendorId', Win32_GUID)
]
class VirtualDisk(object):
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
VIRTUAL_DISK_ACCESS_ATTACH_RO = 0x10000
VIRTUAL_DISK_ACCESS_READ = 0xd0000
OPEN_VIRTUAL_DISK_FLAG_NONE = 0
DETACH_VIRTUAL_DISK_FLAG_NONE = 0
ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY = 1
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER = 2
def __init__(self, path):
self._path = path
self._handle = 0
def _load_virtdisk_dll(self):
global virtdisk
if not virtdisk:
virtdisk = windll.virtdisk
def open(self):
if self._handle:
self.close()
self._load_virtdisk_dll()
vst = Win32_VIRTUAL_STORAGE_TYPE()
vst.DeviceId = self.VIRTUAL_STORAGE_TYPE_DEVICE_ISO
vst.VendorId = get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT()
handle = wintypes.HANDLE()
ret_val = virtdisk.OpenVirtualDisk(ctypes.byref(vst),
ctypes.c_wchar_p(self._path),
self.VIRTUAL_DISK_ACCESS_ATTACH_RO |
self.VIRTUAL_DISK_ACCESS_READ,
self.OPEN_VIRTUAL_DISK_FLAG_NONE, 0,
ctypes.byref(handle))
if ret_val:
raise Exception("Cannot open virtual disk")
self._handle = handle
def attach(self):
ret_val = virtdisk.AttachVirtualDisk(
self._handle, 0, self.ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY, 0, 0, 0)
if ret_val:
raise Exception("Cannot attach virtual disk")
def detach(self):
ret_val = virtdisk.DetachVirtualDisk(
self._handle, self.DETACH_VIRTUAL_DISK_FLAG_NONE, 0)
if ret_val:
raise Exception("Cannot detach virtual disk")
def get_physical_path(self):
buf = ctypes.create_unicode_buffer(1024)
bufLen = wintypes.DWORD(ctypes.sizeof(buf))
ret_val = virtdisk.GetVirtualDiskPhysicalPath(self._handle,
ctypes.byref(bufLen),
buf)
if ret_val:
raise Exception("Cannot get virtual disk physical path")
return buf.value
def get_cdrom_drive_mount_point(self):
mount_point = None
buf = ctypes.create_unicode_buffer(2048)
buf_len = kernel32.GetLogicalDriveStringsW(
ctypes.sizeof(buf) / ctypes.sizeof(wintypes.WCHAR), buf)
if not buf_len:
raise Exception("Cannot enumerate logical devices")
cdrom_dev = self.get_physical_path().rsplit('\\')[-1].upper()
i = 0
while not mount_point and i < buf_len:
curr_drive = ctypes.wstring_at(ctypes.addressof(buf) + i *
ctypes.sizeof(wintypes.WCHAR))[:-1]
dev = ctypes.create_unicode_buffer(2048)
ret_val = kernel32.QueryDosDeviceW(curr_drive, dev,
ctypes.sizeof(dev) /
ctypes.sizeof(wintypes.WCHAR))
if not ret_val:
raise Exception("Cannot query NT device")
if dev.value.rsplit('\\')[-1].upper() == cdrom_dev:
mount_point = curr_drive
else:
i += len(curr_drive) + 2
return mount_point
def close(self):
kernel32.CloseHandle(self._handle)
self._handle = 0
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import ctypes
from ctypes import windll
from ctypes import wintypes
kernel32 = windll.kernel32
# VirtDisk.dll is available starting from Windows Server 2008 R2 / Windows7
virtdisk = None
class Win32_GUID(ctypes.Structure):
_fields_ = [("Data1", wintypes.DWORD),
("Data2", wintypes.WORD),
("Data3", wintypes.WORD),
("Data4", wintypes.BYTE * 8)]
def get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT():
guid = Win32_GUID()
guid.Data1 = 0xec984aec
guid.Data2 = 0xa0f9
guid.Data3 = 0x47e9
ByteArray8 = wintypes.BYTE * 8
guid.Data4 = ByteArray8(0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b)
return guid
class Win32_VIRTUAL_STORAGE_TYPE(ctypes.Structure):
_fields_ = [
('DeviceId', wintypes.DWORD),
('VendorId', Win32_GUID)
]
class VirtualDisk(object):
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
VIRTUAL_DISK_ACCESS_ATTACH_RO = 0x10000
VIRTUAL_DISK_ACCESS_READ = 0xd0000
OPEN_VIRTUAL_DISK_FLAG_NONE = 0
DETACH_VIRTUAL_DISK_FLAG_NONE = 0
ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY = 1
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER = 2
def __init__(self, path):
self._path = path
self._handle = 0
def _load_virtdisk_dll(self):
global virtdisk
if not virtdisk:
virtdisk = windll.virtdisk
def open(self):
if self._handle:
self.close()
self._load_virtdisk_dll()
vst = Win32_VIRTUAL_STORAGE_TYPE()
vst.DeviceId = self.VIRTUAL_STORAGE_TYPE_DEVICE_ISO
vst.VendorId = get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT()
handle = wintypes.HANDLE()
ret_val = virtdisk.OpenVirtualDisk(ctypes.byref(vst),
ctypes.c_wchar_p(self._path),
self.VIRTUAL_DISK_ACCESS_ATTACH_RO |
self.VIRTUAL_DISK_ACCESS_READ,
self.OPEN_VIRTUAL_DISK_FLAG_NONE, 0,
ctypes.byref(handle))
if ret_val:
raise Exception("Cannot open virtual disk")
self._handle = handle
def attach(self):
ret_val = virtdisk.AttachVirtualDisk(
self._handle, 0, self.ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY, 0, 0, 0)
if ret_val:
raise Exception("Cannot attach virtual disk")
def detach(self):
ret_val = virtdisk.DetachVirtualDisk(
self._handle, self.DETACH_VIRTUAL_DISK_FLAG_NONE, 0)
if ret_val:
raise Exception("Cannot detach virtual disk")
def get_physical_path(self):
buf = ctypes.create_unicode_buffer(1024)
bufLen = wintypes.DWORD(ctypes.sizeof(buf))
ret_val = virtdisk.GetVirtualDiskPhysicalPath(self._handle,
ctypes.byref(bufLen),
buf)
if ret_val:
raise Exception("Cannot get virtual disk physical path")
return buf.value
def get_cdrom_drive_mount_point(self):
mount_point = None
buf = ctypes.create_unicode_buffer(2048)
buf_len = kernel32.GetLogicalDriveStringsW(
ctypes.sizeof(buf) / ctypes.sizeof(wintypes.WCHAR), buf)
if not buf_len:
raise Exception("Cannot enumerate logical devices")
cdrom_dev = self.get_physical_path().rsplit('\\')[-1].upper()
i = 0
while not mount_point and i < buf_len:
curr_drive = ctypes.wstring_at(ctypes.addressof(buf) + i *
ctypes.sizeof(wintypes.WCHAR))[:-1]
dev = ctypes.create_unicode_buffer(2048)
ret_val = kernel32.QueryDosDeviceW(curr_drive, dev,
ctypes.sizeof(dev) /
ctypes.sizeof(wintypes.WCHAR))
if not ret_val:
raise Exception("Cannot query NT device")
if dev.value.rsplit('\\')[-1].upper() == cdrom_dev:
mount_point = curr_drive
else:
i += len(curr_drive) + 2
return mount_point
def close(self):
kernel32.CloseHandle(self._handle)
self._handle = 0

View File

@ -1,123 +1,123 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Mirantis Inc.
#
# 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.
import posixpath
import urllib2
import traceback
import os
from cloudbaseinit.metadata.services import base
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.openstack.common import log as logging
opts = [
cfg.StrOpt('ec2_metadata_base_url',
default='http://169.254.169.254/2009-04-04/',
help='The base URL where the service looks for metadata'),
]
ec2nodes = [
'ami-id', 'ami-launch-index', 'ami-manifest-path', 'ancestor-ami-ids',
'hostname', 'block-device-mapping', 'kernel-id',
'placement/availability-zone', 'instance-action', 'instance-id',
'instance-type', 'product-codes', 'local-hostname', 'local-ipv4',
'public-hostname', 'public-ipv4', 'ramdisk-id', 'reservation-id',
'security-groups', 'public-keys/', 'public-keys/0/',
'public-keys/0/openssh-key', 'admin_pass']
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class EC2Service(base.BaseMetadataService):
def __init__(self):
super(EC2Service, self).__init__()
self._enable_retry = True
self.error_count = 0
def load(self):
super(EC2Service, self).load()
try:
self.get_meta_data('openstack')
return True
except Exception, err:
LOG.debug(err)
LOG.debug(traceback.format_exc())
LOG.debug('Metadata not found at URL \'%s\'' %
CONF.ec2_metadata_base_url)
return False
def _get_data(self, path):
data = {}
LOG.debug("Check for EC2 interface availability...")
if not self._check_EC2():
raise Exception("EC2 interface is not available")
LOG.debug('Getting data for the path: %s' % path)
if path.endswith('meta_data.json'):
for key in ec2nodes:
LOG.debug('Getting metadata from: %s' % key)
try:
data[key] = self._get_EC2_value(key)
except:
LOG.info("EC2 value %s is not available. Skip it." % key)
# Saving keys to the local folder
self._load_public_keys(data)
if path.endswith('user_data'):
norm_path = posixpath.join(CONF.ec2_metadata_base_url, 'user-data')
LOG.debug('Getting metadata from: %(norm_path)s' % locals())
try:
req = urllib2.Request(norm_path)
response = urllib2.urlopen(req)
data = response.read()
LOG.debug("Got data: %s" % data)
except:
LOG.error("EC2 user-data is not available.")
return data
def _check_EC2(self):
try:
data = self._get_EC2_value('')
return True
except:
return False
def _get_EC2_value(self, key):
meta_path = posixpath.join(
CONF.ec2_metadata_base_url, 'meta-data', key)
req = urllib2.Request(meta_path)
response = urllib2.urlopen(req)
return response.read()
def _load_public_keys(self, data):
try:
key_list = self._get_EC2_value('public-keys/')
LOG.debug("Got a list of keys %s" % key_list)
data['public_keys'] = {}
for key_name in key_list.split('\n'):
key_index = key_name.split('=')[0]
LOG.debug('Loading key %s' % key_index)
key = self._get_EC2_value(
'public-keys/%s/openssh-key' % key_index)
data['public_keys'].update({key_index: key})
except Exception, ex:
LOG.debug("Can't save public key %s" % ex)
LOG.debug(traceback.format_exc())
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Mirantis Inc.
#
# 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.
import posixpath
import urllib2
import traceback
import os
from cloudbaseinit.metadata.services import base
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.openstack.common import log as logging
opts = [
cfg.StrOpt('ec2_metadata_base_url',
default='http://169.254.169.254/2009-04-04/',
help='The base URL where the service looks for metadata'),
]
ec2nodes = [
'ami-id', 'ami-launch-index', 'ami-manifest-path', 'ancestor-ami-ids',
'hostname', 'block-device-mapping', 'kernel-id',
'placement/availability-zone', 'instance-action', 'instance-id',
'instance-type', 'product-codes', 'local-hostname', 'local-ipv4',
'public-hostname', 'public-ipv4', 'ramdisk-id', 'reservation-id',
'security-groups', 'public-keys/', 'public-keys/0/',
'public-keys/0/openssh-key', 'admin_pass']
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class EC2Service(base.BaseMetadataService):
def __init__(self):
super(EC2Service, self).__init__()
self._enable_retry = True
self.error_count = 0
def load(self):
super(EC2Service, self).load()
try:
self.get_meta_data('openstack')
return True
except Exception, err:
LOG.debug(err)
LOG.debug(traceback.format_exc())
LOG.debug('Metadata not found at URL \'%s\'' %
CONF.ec2_metadata_base_url)
return False
def _get_data(self, path):
data = {}
LOG.debug("Check for EC2 interface availability...")
if not self._check_EC2():
raise Exception("EC2 interface is not available")
LOG.debug('Getting data for the path: %s' % path)
if path.endswith('meta_data.json'):
for key in ec2nodes:
LOG.debug('Getting metadata from: %s' % key)
try:
data[key] = self._get_EC2_value(key)
except:
LOG.info("EC2 value %s is not available. Skip it." % key)
# Saving keys to the local folder
self._load_public_keys(data)
if path.endswith('user_data'):
norm_path = posixpath.join(CONF.ec2_metadata_base_url, 'user-data')
LOG.debug('Getting metadata from: %(norm_path)s' % locals())
try:
req = urllib2.Request(norm_path)
response = urllib2.urlopen(req)
data = response.read()
LOG.debug("Got data: %s" % data)
except:
LOG.error("EC2 user-data is not available.")
return data
def _check_EC2(self):
try:
data = self._get_EC2_value('')
return True
except:
return False
def _get_EC2_value(self, key):
meta_path = posixpath.join(
CONF.ec2_metadata_base_url, 'meta-data', key)
req = urllib2.Request(meta_path)
response = urllib2.urlopen(req)
return response.read()
def _load_public_keys(self, data):
try:
key_list = self._get_EC2_value('public-keys/')
LOG.debug("Got a list of keys %s" % key_list)
data['public_keys'] = {}
for key_name in key_list.split('\n'):
key_index = key_name.split('=')[0]
LOG.debug('Loading key %s' % key_index)
key = self._get_EC2_value(
'public-keys/%s/openssh-key' % key_index)
data['public_keys'].update({key_index: key})
except Exception, ex:
LOG.debug("Can't save public key %s" % ex)
LOG.debug(traceback.format_exc())

View File

@ -1,117 +1,117 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import posixpath
import urllib2
import urlparse
from cloudbaseinit.metadata.services import base
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.osutils import factory as osutils_factory
opts = [
cfg.StrOpt('metadata_base_url', default='http://169.254.169.254/',
help='The base URL where the service looks for metadata'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class HttpService(base.BaseMetadataService):
def __init__(self):
super(HttpService, self).__init__()
self._enable_retry = True
def _check_metadata_ip_route(self):
'''
Workaround for: https://bugs.launchpad.net/quantum/+bug/1174657
'''
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
if osutils.check_os_version(6, 0):
# 169.254.x.x addresses are not getting routed starting from
# Windows Vista / 2008
metadata_netloc = urlparse.urlparse(CONF.metadata_base_url).netloc
metadata_host = metadata_netloc.split(':')[0]
if metadata_host.startswith("169.254."):
if not osutils.check_static_route_exists(metadata_host):
(interface_index, gateway) = osutils.get_default_gateway()
if gateway:
try:
osutils.add_static_route(metadata_host,
"255.255.255.255",
gateway,
interface_index,
10)
except Exception, ex:
# Ignore it
LOG.exception(ex)
def load(self):
super(HttpService, self).load()
self._check_metadata_ip_route()
try:
self.get_meta_data('openstack')
return True
except:
LOG.debug('Metadata not found at URL \'%s\'' %
CONF.metadata_base_url)
return False
@property
def can_post_password(self):
return True
def _get_response(self, req):
try:
return urllib2.urlopen(req)
except urllib2.HTTPError as ex:
if ex.code == 404:
raise base.NotExistingMetadataException()
else:
raise
def _get_data(self, path):
norm_path = posixpath.join(CONF.metadata_base_url, path)
LOG.debug('Getting metadata from: %(norm_path)s' % locals())
req = urllib2.Request(norm_path)
response = self._get_response(req)
return response.read()
def _post_data(self, path, data):
norm_path = posixpath.join(CONF.metadata_base_url, path)
LOG.debug('Posting metadata to: %(norm_path)s' % locals())
req = urllib2.Request(norm_path, data=data)
self._get_response(req)
return True
def post_password(self, enc_password_b64, version='latest'):
try:
return super(HttpService, self).post_password(enc_password_b64,
version)
except urllib2.HTTPError as ex:
if ex.code == 409:
# Password already set
return False
else:
raise
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import posixpath
import urllib2
import urlparse
from cloudbaseinit.metadata.services import base
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.osutils import factory as osutils_factory
opts = [
cfg.StrOpt('metadata_base_url', default='http://169.254.169.254/',
help='The base URL where the service looks for metadata'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
LOG = logging.getLogger(__name__)
class HttpService(base.BaseMetadataService):
def __init__(self):
super(HttpService, self).__init__()
self._enable_retry = True
def _check_metadata_ip_route(self):
'''
Workaround for: https://bugs.launchpad.net/quantum/+bug/1174657
'''
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
if osutils.check_os_version(6, 0):
# 169.254.x.x addresses are not getting routed starting from
# Windows Vista / 2008
metadata_netloc = urlparse.urlparse(CONF.metadata_base_url).netloc
metadata_host = metadata_netloc.split(':')[0]
if metadata_host.startswith("169.254."):
if not osutils.check_static_route_exists(metadata_host):
(interface_index, gateway) = osutils.get_default_gateway()
if gateway:
try:
osutils.add_static_route(metadata_host,
"255.255.255.255",
gateway,
interface_index,
10)
except Exception, ex:
# Ignore it
LOG.exception(ex)
def load(self):
super(HttpService, self).load()
self._check_metadata_ip_route()
try:
self.get_meta_data('openstack')
return True
except:
LOG.debug('Metadata not found at URL \'%s\'' %
CONF.metadata_base_url)
return False
@property
def can_post_password(self):
return True
def _get_response(self, req):
try:
return urllib2.urlopen(req)
except urllib2.HTTPError as ex:
if ex.code == 404:
raise base.NotExistingMetadataException()
else:
raise
def _get_data(self, path):
norm_path = posixpath.join(CONF.metadata_base_url, path)
LOG.debug('Getting metadata from: %(norm_path)s' % locals())
req = urllib2.Request(norm_path)
response = self._get_response(req)
return response.read()
def _post_data(self, path, data):
norm_path = posixpath.join(CONF.metadata_base_url, path)
LOG.debug('Posting metadata to: %(norm_path)s' % locals())
req = urllib2.Request(norm_path, data=data)
self._get_response(req)
return True
def post_password(self, enc_password_b64, version='latest'):
try:
return super(HttpService, self).post_password(enc_password_b64,
version)
except urllib2.HTTPError as ex:
if ex.code == 409:
# Password already set
return False
else:
raise

View File

@ -1,52 +1,52 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.utils import classloader
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.winrmcertificateauth.'
'ConfigWinRMCertificateAuthPlugin',
],
help='List of enabled plugin classes, '
'to executed in the provided order'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
class PluginFactory(object):
def load_plugins(self):
plugins = []
cl = classloader.ClassLoader()
for class_path in CONF.plugins:
plugins.append(cl.load_class(class_path)())
return plugins
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
from cloudbaseinit.openstack.common import cfg
from cloudbaseinit.utils import classloader
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.winrmcertificateauth.'
'ConfigWinRMCertificateAuthPlugin',
],
help='List of enabled plugin classes, '
'to executed in the provided order'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
class PluginFactory(object):
def load_plugins(self):
plugins = []
cl = classloader.ClassLoader()
for class_path in CONF.plugins:
plugins.append(cl.load_class(class_path)())
return plugins

View File

@ -1,85 +1,85 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import re
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
LOG = logging.getLogger(__name__)
opts = [
cfg.StrOpt('network_adapter', default=None, help='Network adapter to '
'configure. If not specified, the first available ethernet '
'adapter will be chosen'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
class NetworkConfigPlugin(base.BasePlugin):
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)
network_config = meta_data['network_config']
if 'content_path' not in network_config:
return (base.PLUGIN_EXECUTION_DONE, False)
content_path = network_config['content_path']
content_name = content_path.rsplit('/', 1)[-1]
debian_network_conf = service.get_content('openstack', content_name)
LOG.debug('network config content:\n%s' % debian_network_conf)
# TODO (alexpilotti): implement a proper grammar
m = re.search(r'iface eth0 inet static\s+'
r'address\s+(?P<address>[^\s]+)\s+'
r'netmask\s+(?P<netmask>[^\s]+)\s+'
r'broadcast\s+(?P<broadcast>[^\s]+)\s+'
r'gateway\s+(?P<gateway>[^\s]+)\s+'
r'dns\-nameservers\s+(?P<dnsnameservers>[^\r\n]+)\s+',
debian_network_conf)
if not m:
raise Exception("network_config format not recognized")
address = m.group('address')
netmask = m.group('netmask')
broadcast = m.group('broadcast')
gateway = m.group('gateway')
dnsnameservers = m.group('dnsnameservers').strip().split(' ')
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
network_adapter_name = CONF.network_adapter
if not network_adapter_name:
# Get the first available one
available_adapters = osutils.get_network_adapters()
if not len(available_adapters):
raise Exception("No network adapter available")
network_adapter_name = available_adapters[0]
LOG.info('Configuring network adapter: \'%s\'' % network_adapter_name)
reboot_required = osutils.set_static_network_config(
network_adapter_name, address, netmask, broadcast,
gateway, dnsnameservers)
return (base.PLUGIN_EXECUTION_DONE, reboot_required)
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import re
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
LOG = logging.getLogger(__name__)
opts = [
cfg.StrOpt('network_adapter', default=None, help='Network adapter to '
'configure. If not specified, the first available ethernet '
'adapter will be chosen'),
]
CONF = cfg.CONF
CONF.register_opts(opts)
class NetworkConfigPlugin(base.BasePlugin):
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)
network_config = meta_data['network_config']
if 'content_path' not in network_config:
return (base.PLUGIN_EXECUTION_DONE, False)
content_path = network_config['content_path']
content_name = content_path.rsplit('/', 1)[-1]
debian_network_conf = service.get_content('openstack', content_name)
LOG.debug('network config content:\n%s' % debian_network_conf)
# TODO (alexpilotti): implement a proper grammar
m = re.search(r'iface eth0 inet static\s+'
r'address\s+(?P<address>[^\s]+)\s+'
r'netmask\s+(?P<netmask>[^\s]+)\s+'
r'broadcast\s+(?P<broadcast>[^\s]+)\s+'
r'gateway\s+(?P<gateway>[^\s]+)\s+'
r'dns\-nameservers\s+(?P<dnsnameservers>[^\r\n]+)\s+',
debian_network_conf)
if not m:
raise Exception("network_config format not recognized")
address = m.group('address')
netmask = m.group('netmask')
broadcast = m.group('broadcast')
gateway = m.group('gateway')
dnsnameservers = m.group('dnsnameservers').strip().split(' ')
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
network_adapter_name = CONF.network_adapter
if not network_adapter_name:
# Get the first available one
available_adapters = osutils.get_network_adapters()
if not len(available_adapters):
raise Exception("No network adapter available")
network_adapter_name = available_adapters[0]
LOG.info('Configuring network adapter: \'%s\'' % network_adapter_name)
reboot_required = osutils.set_static_network_config(
network_adapter_name, address, netmask, broadcast,
gateway, dnsnameservers)
return (base.PLUGIN_EXECUTION_DONE, reboot_required)

View File

@ -1,145 +1,145 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import email
from cloudbaseinit.metadata.services import base as metadata_services_base
from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.plugins import base
from cloudbaseinit.plugins.windows import userdatautils
from cloudbaseinit.plugins.windows.userdataplugins import factory
LOG = logging.getLogger(__name__)
class UserDataPlugin(base.BasePlugin):
_part_handler_content_type = "text/part-handler"
def execute(self, service, shared_data):
try:
user_data = service.get_user_data('openstack')
except metadata_services_base.NotExistingMetadataException:
return (base.PLUGIN_EXECUTION_DONE, False)
if not user_data:
return (base.PLUGIN_EXECUTION_DONE, False)
return self._process_user_data(user_data)
def _parse_mime(self, user_data):
return email.message_from_string(user_data).walk()
def _process_user_data(self, user_data):
plugin_status = base.PLUGIN_EXECUTION_DONE
reboot = False
LOG.debug('User data content:\n%s' % user_data)
if user_data.startswith('Content-Type: multipart'):
user_data_plugins_factory = factory.UserDataPluginsFactory()
user_data_plugins = user_data_plugins_factory.load_plugins()
user_handlers = {}
for part in self._parse_mime(user_data):
(plugin_status, reboot) = self._process_part(part,
user_data_plugins,
user_handlers)
if reboot:
break
if not reboot:
for handler_func in list(set(user_handlers.values())):
self._end_part_process_event(handler_func)
return (plugin_status, reboot)
else:
return self._process_non_multi_part(user_data)
def _process_part(self, part, user_data_plugins, user_handlers):
ret_val = None
try:
content_type = part.get_content_type()
handler_func = user_handlers.get(content_type)
if handler_func:
LOG.debug("Calling user part handler for content type: %s" %
content_type)
handler_func(None, content_type, part.get_filename(),
part.get_payload())
else:
user_data_plugin = user_data_plugins.get(content_type)
if not user_data_plugin:
LOG.info("Userdata plugin not found for content type: %s" %
content_type)
else:
LOG.debug("Executing userdata plugin: %s" %
user_data_plugin.__class__.__name__)
if content_type == self._part_handler_content_type:
new_user_handlers = user_data_plugin.process(part)
self._add_part_handlers(user_data_plugins,
user_handlers,
new_user_handlers)
else:
ret_val = user_data_plugin.process(part)
except Exception, ex:
LOG.error('Exception during multipart part handling: '
'%(content_type)s, %(filename)s' %
{'content_type': part.get_content_type(),
'filename': part.get_filename()})
LOG.exception(ex)
return self._get_plugin_return_value(ret_val)
def _add_part_handlers(self, user_data_plugins, user_handlers,
new_user_handlers):
handler_funcs = set()
for (content_type,
handler_func) in new_user_handlers.items():
if not user_data_plugins.get(content_type):
LOG.info("Adding part handler for content "
"type: %s" % content_type)
user_handlers[content_type] = handler_func
handler_funcs.add(handler_func)
else:
LOG.info("Skipping part handler for content type \"%s\" as it "
"is already managed by a plugin" % content_type)
for handler_func in handler_funcs:
self._begin_part_process_event(handler_func)
def _begin_part_process_event(self, handler_func):
LOG.debug("Calling part handler \"__begin__\" event")
handler_func(None, "__begin__", None, None)
def _end_part_process_event(self, handler_func):
LOG.debug("Calling part handler \"__end__\" event")
handler_func(None, "__end__", None, None)
def _get_plugin_return_value(self, ret_val):
plugin_status = base.PLUGIN_EXECUTION_DONE
reboot = False
if ret_val >= 1001 and ret_val <= 1003:
reboot = bool(ret_val & 1)
if ret_val & 2:
plugin_status = base.PLUGIN_EXECUTE_ON_NEXT_BOOT
return (plugin_status, reboot)
def _process_non_multi_part(self, user_data):
ret_val = userdatautils.execute_user_data_script(user_data)
return self._get_plugin_return_value(ret_val)
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 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.
import email
from cloudbaseinit.metadata.services import base as metadata_services_base
from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.plugins import base
from cloudbaseinit.plugins.windows import userdatautils
from cloudbaseinit.plugins.windows.userdataplugins import factory
LOG = logging.getLogger(__name__)
class UserDataPlugin(base.BasePlugin):
_part_handler_content_type = "text/part-handler"
def execute(self, service, shared_data):
try:
user_data = service.get_user_data('openstack')
except metadata_services_base.NotExistingMetadataException:
return (base.PLUGIN_EXECUTION_DONE, False)
if not user_data:
return (base.PLUGIN_EXECUTION_DONE, False)
return self._process_user_data(user_data)
def _parse_mime(self, user_data):
return email.message_from_string(user_data).walk()
def _process_user_data(self, user_data):
plugin_status = base.PLUGIN_EXECUTION_DONE
reboot = False
LOG.debug('User data content:\n%s' % user_data)
if user_data.startswith('Content-Type: multipart'):
user_data_plugins_factory = factory.UserDataPluginsFactory()
user_data_plugins = user_data_plugins_factory.load_plugins()
user_handlers = {}
for part in self._parse_mime(user_data):
(plugin_status, reboot) = self._process_part(part,
user_data_plugins,
user_handlers)
if reboot:
break
if not reboot:
for handler_func in list(set(user_handlers.values())):
self._end_part_process_event(handler_func)
return (plugin_status, reboot)
else:
return self._process_non_multi_part(user_data)
def _process_part(self, part, user_data_plugins, user_handlers):
ret_val = None
try:
content_type = part.get_content_type()
handler_func = user_handlers.get(content_type)
if handler_func:
LOG.debug("Calling user part handler for content type: %s" %
content_type)
handler_func(None, content_type, part.get_filename(),
part.get_payload())
else:
user_data_plugin = user_data_plugins.get(content_type)
if not user_data_plugin:
LOG.info("Userdata plugin not found for content type: %s" %
content_type)
else:
LOG.debug("Executing userdata plugin: %s" %
user_data_plugin.__class__.__name__)
if content_type == self._part_handler_content_type:
new_user_handlers = user_data_plugin.process(part)
self._add_part_handlers(user_data_plugins,
user_handlers,
new_user_handlers)
else:
ret_val = user_data_plugin.process(part)
except Exception, ex:
LOG.error('Exception during multipart part handling: '
'%(content_type)s, %(filename)s' %
{'content_type': part.get_content_type(),
'filename': part.get_filename()})
LOG.exception(ex)
return self._get_plugin_return_value(ret_val)
def _add_part_handlers(self, user_data_plugins, user_handlers,
new_user_handlers):
handler_funcs = set()
for (content_type,
handler_func) in new_user_handlers.items():
if not user_data_plugins.get(content_type):
LOG.info("Adding part handler for content "
"type: %s" % content_type)
user_handlers[content_type] = handler_func
handler_funcs.add(handler_func)
else:
LOG.info("Skipping part handler for content type \"%s\" as it "
"is already managed by a plugin" % content_type)
for handler_func in handler_funcs:
self._begin_part_process_event(handler_func)
def _begin_part_process_event(self, handler_func):
LOG.debug("Calling part handler \"__begin__\" event")
handler_func(None, "__begin__", None, None)
def _end_part_process_event(self, handler_func):
LOG.debug("Calling part handler \"__end__\" event")
handler_func(None, "__end__", None, None)
def _get_plugin_return_value(self, ret_val):
plugin_status = base.PLUGIN_EXECUTION_DONE
reboot = False
if ret_val >= 1001 and ret_val <= 1003:
reboot = bool(ret_val & 1)
if ret_val & 2:
plugin_status = base.PLUGIN_EXECUTE_ON_NEXT_BOOT
return (plugin_status, reboot)
def _process_non_multi_part(self, user_data):
ret_val = userdatautils.execute_user_data_script(user_data)
return self._get_plugin_return_value(ret_val)