pylint and pep8
This commit is contained in:
parent
6debb9d40e
commit
fcd8271c5b
@ -14,16 +14,11 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import sys
|
||||
|
||||
from cloudbaseinit.metadata.factory import *
|
||||
from cloudbaseinit.openstack.common import cfg
|
||||
from cloudbaseinit.metadata import factory as metadata_factory
|
||||
from cloudbaseinit.openstack.common import log as logging
|
||||
from cloudbaseinit.osutils.factory import *
|
||||
from cloudbaseinit.plugins.factory import *
|
||||
from cloudbaseinit.utils import *
|
||||
from cloudbaseinit.osutils import factory as osutils_factory
|
||||
from cloudbaseinit.plugins import factory as plugins_factory
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -35,18 +30,19 @@ class InitManager(object):
|
||||
|
||||
def _mark_as_configured(self, osutils):
|
||||
osutils.set_config_value(self._config_done_key, 1)
|
||||
|
||||
|
||||
def configure_host(self):
|
||||
osutils = OSUtilsFactory().get_os_utils()
|
||||
|
||||
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
|
||||
|
||||
if self._is_already_configured(osutils):
|
||||
LOG.info('Host already configured, skipping configuration')
|
||||
return
|
||||
|
||||
plugins = PluginFactory().load_plugins()
|
||||
service = MetadataServiceFactory().get_metadata_service()
|
||||
|
||||
plugins = plugins_factory.PluginFactory().load_plugins()
|
||||
mdsf = metadata_factory.MetadataServiceFactory()
|
||||
service = mdsf.get_metadata_service()
|
||||
LOG.info('Metadata service loaded: \'%s\'' %
|
||||
service.__class__.__name__)
|
||||
service.__class__.__name__)
|
||||
|
||||
reboot_required = False
|
||||
try:
|
||||
@ -59,12 +55,12 @@ class InitManager(object):
|
||||
reboot_required = True
|
||||
except Exception, ex:
|
||||
LOG.error('plugin \'%(plugin_name)s\' failed '
|
||||
'with error \'%(ex)s\'' % locals())
|
||||
'with error \'%(ex)s\'' % locals())
|
||||
finally:
|
||||
service.cleanup()
|
||||
|
||||
self._mark_as_configured(osutils)
|
||||
|
||||
|
||||
if reboot_required:
|
||||
try:
|
||||
osutils.reboot()
|
||||
|
@ -19,16 +19,18 @@ 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')
|
||||
]
|
||||
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)
|
||||
@ -46,6 +48,5 @@ class MetadataServiceFactory(object):
|
||||
return service
|
||||
except Exception, ex:
|
||||
LOG.error('Failed to load metadata service \'%(class_path)s\' '
|
||||
'with error: %(ex)s'%
|
||||
locals())
|
||||
'with error: %(ex)s' % locals())
|
||||
raise Exception("No available service found")
|
||||
|
@ -24,12 +24,12 @@ from cloudbaseinit.openstack.common import log as logging
|
||||
|
||||
opts = [
|
||||
cfg.IntOpt('retry_count', default=5,
|
||||
help='Max. number of attempts for fetching metadata in '
|
||||
'case of transient errors'),
|
||||
help='Max. number of attempts for fetching metadata in '
|
||||
'case of transient errors'),
|
||||
cfg.FloatOpt('retry_count_interval', default=4,
|
||||
help='Interval between attempts in case of transient errors, '
|
||||
'expressed in seconds'),
|
||||
]
|
||||
help='Interval between attempts in case of transient errors, '
|
||||
'expressed in seconds'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(opts)
|
||||
|
@ -14,23 +14,22 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
from cloudbaseinit.metadata.services.base import *
|
||||
from cloudbaseinit.metadata.services import base
|
||||
from cloudbaseinit.openstack.common import cfg
|
||||
from cloudbaseinit.openstack.common import log as logging
|
||||
from manager import *
|
||||
from cloudbaseinit.metadata.services.configdrive import manager
|
||||
|
||||
opts = [
|
||||
cfg.BoolOpt('config_drive_raw_hhd', default=True,
|
||||
help='Look for an ISO config drive in raw HDDs'),
|
||||
help='Look for an ISO config drive in raw HDDs'),
|
||||
cfg.BoolOpt('config_drive_cdrom', default=True,
|
||||
help='Look for a config drive in the attached cdrom drives'),
|
||||
]
|
||||
help='Look for a config drive in the attached cdrom drives'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(opts)
|
||||
@ -38,7 +37,7 @@ CONF.register_opts(opts)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ConfigDriveService(BaseMetadataService):
|
||||
class ConfigDriveService(base.BaseMetadataService):
|
||||
def __init__(self):
|
||||
self._metadata_path = None
|
||||
|
||||
@ -47,12 +46,14 @@ class ConfigDriveService(BaseMetadataService):
|
||||
|
||||
target_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4()))
|
||||
|
||||
mgr = ConfigDriveManager()
|
||||
mgr = manager.ConfigDriveManager()
|
||||
found = mgr.get_config_drive_files(target_path,
|
||||
CONF.config_drive_raw_hhd, CONF.config_drive_cdrom)
|
||||
CONF.config_drive_raw_hhd,
|
||||
CONF.config_drive_cdrom)
|
||||
if found:
|
||||
self._metadata_path = target_path
|
||||
LOG.debug('Metadata copied to folder: \'%s\'' % self._metadata_path)
|
||||
LOG.debug('Metadata copied to folder: \'%s\'' %
|
||||
self._metadata_path)
|
||||
return found
|
||||
|
||||
def _get_data(self, path):
|
||||
|
@ -26,8 +26,10 @@ from ctypes import wintypes
|
||||
|
||||
from cloudbaseinit.openstack.common import log as logging
|
||||
|
||||
from windows.disk import physical_disk
|
||||
from windows.disk import virtual_disk
|
||||
from cloudbaseinit.metadata.services.configdrive.windows.disk \
|
||||
import physical_disk
|
||||
from cloudbaseinit.metadata.services.configdrive.windows.disk \
|
||||
import virtual_disk
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -38,41 +40,45 @@ class ConfigDriveManager(object):
|
||||
conn = wmi.WMI(moniker='//./root/cimv2')
|
||||
q = conn.query('SELECT DeviceID FROM Win32_DiskDrive')
|
||||
for r in q:
|
||||
l.append(r.DeviceID)
|
||||
l.append(r.DeviceID)
|
||||
return l
|
||||
|
||||
def _get_config_drive_cdrom_mount_point(self):
|
||||
conn = wmi.WMI(moniker='//./root/cimv2')
|
||||
q = conn.query('SELECT Drive FROM Win32_CDROMDrive WHERE MediaLoaded = True')
|
||||
q = conn.query('SELECT Drive FROM Win32_CDROMDrive WHERE '
|
||||
'MediaLoaded = True')
|
||||
for r in q:
|
||||
drive = r.Drive + '\\'
|
||||
q1 = conn.query('SELECT Label FROM Win32_Volume WHERE Name = \'%(drive)s\'' % locals())
|
||||
q1 = conn.query('SELECT Label FROM Win32_Volume WHERE '
|
||||
'Name = \'%(drive)s\'' % locals())
|
||||
for r1 in q1:
|
||||
if r1.Label == "config-2" and \
|
||||
os.path.exists(os.path.join(drive, 'openstack\\latest\\meta_data.json')):
|
||||
os.path.exists(os.path.join(drive,
|
||||
'openstack\\latest\\'
|
||||
'meta_data.json')):
|
||||
return drive
|
||||
return None
|
||||
|
||||
def _c_char_array_to_c_ushort(self, buf, offset):
|
||||
low = ctypes.cast(buf[offset],
|
||||
ctypes.POINTER(wintypes.WORD)).contents
|
||||
ctypes.POINTER(wintypes.WORD)).contents
|
||||
high = ctypes.cast(buf[offset + 1],
|
||||
ctypes.POINTER(wintypes.WORD)).contents
|
||||
ctypes.POINTER(wintypes.WORD)).contents
|
||||
return (high.value << 8) + low.value
|
||||
|
||||
def _get_iso_disk_size(self, phys_disk):
|
||||
geom = phys_disk.get_geometry()
|
||||
|
||||
if geom.MediaType != Win32_DiskGeometry.FixedMedia:
|
||||
if geom.MediaType != physical_disk.Win32_DiskGeometry.FixedMedia:
|
||||
return None
|
||||
|
||||
disk_size = geom.Cylinders * geom.TracksPerCylinder * \
|
||||
geom.SectorsPerTrack * geom.BytesPerSector
|
||||
|
||||
boot_record_off = 0x8000;
|
||||
id_off = 1;
|
||||
volume_size_off = 80;
|
||||
block_size_off = 128;
|
||||
boot_record_off = 0x8000
|
||||
id_off = 1
|
||||
volume_size_off = 80
|
||||
block_size_off = 128
|
||||
iso_id = 'CD001'
|
||||
|
||||
offset = boot_record_off / geom.BytesPerSector * geom.BytesPerSector
|
||||
@ -85,7 +91,7 @@ class ConfigDriveManager(object):
|
||||
(buf, bytes_read) = phys_disk.read(bytes_to_read)
|
||||
|
||||
buf_off = boot_record_off - offset + id_off
|
||||
if iso_id != buf[buf_off : buf_off + len(iso_id)]:
|
||||
if iso_id != buf[buf_off: buf_off + len(iso_id)]:
|
||||
return None
|
||||
|
||||
buf_off = boot_record_off - offset + volume_size_off
|
||||
@ -136,7 +142,7 @@ class ConfigDriveManager(object):
|
||||
iso_file_size = self._get_iso_disk_size(phys_disk)
|
||||
if iso_file_size:
|
||||
self._write_iso_file(phys_disk, iso_file_path,
|
||||
iso_file_size)
|
||||
iso_file_size)
|
||||
iso_disk_found = True
|
||||
break
|
||||
except:
|
||||
@ -148,14 +154,15 @@ class ConfigDriveManager(object):
|
||||
|
||||
def _os_supports_iso_virtual_disks(self):
|
||||
# Feature supported starting from Windows 8 / 2012
|
||||
ver = sys.getwindowsversion();
|
||||
ver = sys.getwindowsversion()
|
||||
supported = (ver[0] >= 6 and ver[1] >= 2)
|
||||
if not supported:
|
||||
LOG.debug('ISO virtual disks are not supported on '
|
||||
'this version of Windows')
|
||||
'this version of Windows')
|
||||
return supported
|
||||
|
||||
def get_config_drive_files(self, target_path, check_raw_hhd=True, check_cdrom=True):
|
||||
def get_config_drive_files(self, target_path, check_raw_hhd=True,
|
||||
check_cdrom=True):
|
||||
config_drive_found = False
|
||||
if check_raw_hhd and self._os_supports_iso_virtual_disks():
|
||||
LOG.debug('Looking for Config Drive in raw HDDs')
|
||||
@ -178,7 +185,7 @@ class ConfigDriveManager(object):
|
||||
def _get_conf_drive_from_raw_hdd(self, target_path):
|
||||
config_drive_found = False
|
||||
iso_file_path = os.path.join(tempfile.gettempdir(),
|
||||
str(uuid.uuid4()) + '.iso')
|
||||
str(uuid.uuid4()) + '.iso')
|
||||
try:
|
||||
if self._extract_iso_disk_file(iso_file_path):
|
||||
self._copy_iso_files(iso_file_path, target_path)
|
||||
@ -187,4 +194,3 @@ class ConfigDriveManager(object):
|
||||
if os.path.exists(iso_file_path):
|
||||
os.remove(iso_file_path)
|
||||
return config_drive_found
|
||||
|
||||
|
@ -93,7 +93,8 @@ class PhysicalDisk(object):
|
||||
low = wintypes.DWORD(offset & 0xFFFFFFFFL)
|
||||
|
||||
ret_val = kernel32.SetFilePointer(self._handle, low,
|
||||
ctypes.byref(high), self.FILE_BEGIN)
|
||||
ctypes.byref(high),
|
||||
self.FILE_BEGIN)
|
||||
if ret_val == self.INVALID_SET_FILE_POINTER:
|
||||
raise Exception("Seek error")
|
||||
|
||||
@ -101,7 +102,7 @@ class PhysicalDisk(object):
|
||||
buf = ctypes.create_string_buffer(bytes_to_read)
|
||||
bytes_read = wintypes.DWORD()
|
||||
ret_val = kernel32.ReadFile(self._handle, buf, bytes_to_read,
|
||||
ctypes.byref(bytes_read), 0)
|
||||
ctypes.byref(bytes_read), 0)
|
||||
if not ret_val:
|
||||
raise Exception("Read exception")
|
||||
return (buf, bytes_read.value)
|
||||
|
@ -36,7 +36,7 @@ def get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT():
|
||||
guid.Data1 = 0xec984aec
|
||||
guid.Data2 = 0xa0f9
|
||||
guid.Data3 = 0x47e9
|
||||
ByteArray8 = wintypes.BYTE * 8;
|
||||
ByteArray8 = wintypes.BYTE * 8
|
||||
guid.Data4 = ByteArray8(0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b)
|
||||
return guid
|
||||
|
||||
@ -77,31 +77,34 @@ class VirtualDisk(object):
|
||||
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))
|
||||
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)
|
||||
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)
|
||||
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));
|
||||
bufLen = wintypes.DWORD(ctypes.sizeof(buf))
|
||||
ret_val = virtdisk.GetVirtualDiskPhysicalPath(self._handle,
|
||||
ctypes.byref(bufLen), buf)
|
||||
ctypes.byref(bufLen),
|
||||
buf)
|
||||
if ret_val:
|
||||
raise Exception("Cannot get virtual disk physical path")
|
||||
return buf.value
|
||||
@ -120,12 +123,13 @@ class VirtualDisk(object):
|
||||
|
||||
i = 0
|
||||
while not mount_point and i < buf_len:
|
||||
curr_drive = ctypes.wstring_at(ctypes.addressof(buf) + \
|
||||
i * ctypes.sizeof(wintypes.WCHAR))[:-1]
|
||||
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))
|
||||
ctypes.sizeof(dev) /
|
||||
ctypes.sizeof(wintypes.WCHAR))
|
||||
if not ret_val:
|
||||
raise Exception("Cannot query NT device")
|
||||
|
||||
|
@ -27,27 +27,29 @@ 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']
|
||||
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:
|
||||
@ -57,23 +59,23 @@ class EC2Service(base.BaseMetadataService):
|
||||
LOG.debug(err)
|
||||
LOG.debug(traceback.format_exc())
|
||||
LOG.debug('Metadata not found at URL \'%s\'' %
|
||||
CONF.ec2_metadata_base_url)
|
||||
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")
|
||||
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)
|
||||
data[key] = self._get_EC2_value(key)
|
||||
except:
|
||||
LOG.info("EC2 value %s is not available. Skip it." % key)
|
||||
LOG.info("EC2 value %s is not available. Skip it." % key)
|
||||
# Saving keys to the local folder
|
||||
self._load_public_keys(data)
|
||||
|
||||
@ -81,39 +83,41 @@ class EC2Service(base.BaseMetadataService):
|
||||
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)
|
||||
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.")
|
||||
LOG.error("EC2 user-data is not available.")
|
||||
return data
|
||||
|
||||
def _check_EC2(self):
|
||||
try:
|
||||
data = self._get_EC2_value('')
|
||||
return True
|
||||
data = self._get_EC2_value('')
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
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()
|
||||
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())
|
||||
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())
|
||||
|
@ -23,14 +23,15 @@ from cloudbaseinit.openstack.common import log as logging
|
||||
|
||||
opts = [
|
||||
cfg.StrOpt('metadata_base_url', default='http://169.254.169.254/',
|
||||
help='The base URL where the service looks for metadata'),
|
||||
]
|
||||
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__()
|
||||
@ -43,13 +44,13 @@ class HttpService(base.BaseMetadataService):
|
||||
return True
|
||||
except:
|
||||
LOG.debug('Metadata not found at URL \'%s\'' %
|
||||
CONF.metadata_base_url)
|
||||
CONF.metadata_base_url)
|
||||
return False
|
||||
|
||||
@property
|
||||
def can_post_password(self):
|
||||
return True
|
||||
|
||||
|
||||
def _get_response(self, req):
|
||||
try:
|
||||
return urllib2.urlopen(req)
|
||||
@ -83,5 +84,3 @@ class HttpService(base.BaseMetadataService):
|
||||
return False
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
import subprocess
|
||||
|
||||
|
||||
class BaseOSUtils(object):
|
||||
def reboot(self):
|
||||
pass
|
||||
@ -25,9 +26,9 @@ class BaseOSUtils(object):
|
||||
|
||||
def execute_process(self, args, shell=True):
|
||||
p = subprocess.Popen(args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
shell=shell)
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
shell=shell)
|
||||
(out, err) = p.communicate()
|
||||
return (out, err, p.returncode)
|
||||
|
||||
@ -53,7 +54,8 @@ class BaseOSUtils(object):
|
||||
pass
|
||||
|
||||
def set_static_network_config(self, adapter_name, address, netmask,
|
||||
broadcast, gateway, dnsdomain, dnsnameservers):
|
||||
broadcast, gateway, dnsdomain,
|
||||
dnsnameservers):
|
||||
pass
|
||||
|
||||
def set_config_value(self, name, value):
|
||||
@ -61,4 +63,3 @@ class BaseOSUtils(object):
|
||||
|
||||
def get_config_value(self, name):
|
||||
pass
|
||||
|
||||
|
@ -18,12 +18,13 @@ import os
|
||||
|
||||
from cloudbaseinit.utils import classloader
|
||||
|
||||
|
||||
class OSUtilsFactory(object):
|
||||
def get_os_utils(self):
|
||||
osutils_class_paths = {
|
||||
'nt' : 'cloudbaseinit.osutils.windows.WindowsUtils',
|
||||
'posix' : 'cloudbaseinit.osutils.posix.PosixUtils'
|
||||
}
|
||||
'nt': 'cloudbaseinit.osutils.windows.WindowsUtils',
|
||||
'posix': 'cloudbaseinit.osutils.posix.PosixUtils'
|
||||
}
|
||||
|
||||
cl = classloader.ClassLoader()
|
||||
return cl.load_class(osutils_class_paths[os.name])()
|
||||
|
@ -16,8 +16,9 @@
|
||||
|
||||
import os
|
||||
|
||||
from cloudbaseinit.osutils.base import *
|
||||
from cloudbaseinit.osutils import base
|
||||
|
||||
class PosixUtil(BaseOSUtils):
|
||||
|
||||
class PosixUtil(base.BaseOSUtils):
|
||||
def reboot(self):
|
||||
os.system('reboot')
|
||||
|
@ -84,15 +84,17 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
def _get_user_wmi_object(self, username):
|
||||
conn = wmi.WMI(moniker='//./root/cimv2')
|
||||
username_san = self._sanitize_wmi_input(username)
|
||||
q = conn.query('SELECT * FROM Win32_Account where name = \'%(username_san)s\'' % locals())
|
||||
q = conn.query('SELECT * FROM Win32_Account where name = '
|
||||
'\'%(username_san)s\'' % locals())
|
||||
if len(q) > 0:
|
||||
return q[0]
|
||||
return None
|
||||
|
||||
def user_exists(self, username):
|
||||
return self._get_user_wmi_object(username) != None
|
||||
return self._get_user_wmi_object(username) is not None
|
||||
|
||||
def _create_or_change_user(self, username, password, create, password_expires):
|
||||
def _create_or_change_user(self, username, password, create,
|
||||
password_expires):
|
||||
username_san = self.sanitize_shell_input(username)
|
||||
password_san = self.sanitize_shell_input(password)
|
||||
|
||||
@ -119,12 +121,12 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
|
||||
def create_user(self, username, password, password_expires=False):
|
||||
if not self._create_or_change_user(username, password, True,
|
||||
password_expires):
|
||||
password_expires):
|
||||
raise Exception("Create user failed")
|
||||
|
||||
def set_user_password(self, username, password, password_expires=False):
|
||||
if not self._create_or_change_user(username, password, False,
|
||||
password_expires):
|
||||
password_expires):
|
||||
raise Exception("Set user password failed")
|
||||
|
||||
def _get_user_sid_and_domain(self, username):
|
||||
@ -135,10 +137,9 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
ctypes.sizeof(domainName) / ctypes.sizeof(wintypes.WCHAR))
|
||||
sidNameUse = wintypes.DWORD()
|
||||
|
||||
ret_val = advapi32.LookupAccountNameW(0, unicode(username), sid,
|
||||
ctypes.byref(cbSid), domainName,
|
||||
ctypes.byref(cchReferencedDomainName),
|
||||
ctypes.byref(sidNameUse))
|
||||
ret_val = advapi32.LookupAccountNameW(
|
||||
0, unicode(username), sid, ctypes.byref(cbSid), domainName,
|
||||
ctypes.byref(cchReferencedDomainName), ctypes.byref(sidNameUse))
|
||||
if not ret_val:
|
||||
raise Exception("Cannot get user SID")
|
||||
|
||||
@ -150,7 +151,7 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
lmi.lgrmi3_domainandname = unicode(username)
|
||||
|
||||
ret_val = netapi32.NetLocalGroupAddMembers(0, unicode(groupname), 3,
|
||||
ctypes.addressof(lmi), 1)
|
||||
ctypes.addressof(lmi), 1)
|
||||
|
||||
if ret_val == self.NERR_GroupNotFound:
|
||||
raise Exception('Group not found')
|
||||
@ -172,10 +173,12 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
return None
|
||||
return r.SID
|
||||
|
||||
def create_user_logon_session(self, username, password, domain='.', load_profile=True):
|
||||
def create_user_logon_session(self, username, password, domain='.',
|
||||
load_profile=True):
|
||||
token = wintypes.HANDLE()
|
||||
ret_val = advapi32.LogonUserW(unicode(username), unicode(domain),
|
||||
unicode(password), 2, 0, ctypes.byref(token))
|
||||
unicode(password), 2, 0,
|
||||
ctypes.byref(token))
|
||||
if not ret_val:
|
||||
raise Exception("User logon failed")
|
||||
|
||||
@ -196,10 +199,10 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
def get_user_home(self, username):
|
||||
user_sid = self.get_user_sid(username)
|
||||
if user_sid:
|
||||
with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
|
||||
'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s'
|
||||
% user_sid) as key:
|
||||
return _winreg.QueryValueEx(key, 'ProfileImagePath')[0]
|
||||
with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\'
|
||||
'Microsoft\\Windows NT\\CurrentVersion\\'
|
||||
'ProfileList\\%s' % user_sid) as key:
|
||||
return _winreg.QueryValueEx(key, 'ProfileImagePath')[0]
|
||||
LOG.debug('Home directory not found for user \'%s\'' % username)
|
||||
return None
|
||||
|
||||
@ -220,18 +223,18 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
conn = wmi.WMI(moniker='//./root/cimv2')
|
||||
# Get Ethernet adapters only
|
||||
q = conn.query('SELECT * FROM Win32_NetworkAdapter WHERE '
|
||||
'AdapterTypeId = 0 AND PhysicalAdapter = True')
|
||||
'AdapterTypeId = 0 AND PhysicalAdapter = True')
|
||||
for r in q:
|
||||
l.append(r.Name)
|
||||
return l
|
||||
|
||||
def set_static_network_config(self, adapter_name, address, netmask,
|
||||
broadcast, gateway, dnsnameservers):
|
||||
broadcast, gateway, dnsnameservers):
|
||||
conn = wmi.WMI(moniker='//./root/cimv2')
|
||||
|
||||
adapter_name_san = self._sanitize_wmi_input(adapter_name)
|
||||
q = conn.query('SELECT * FROM Win32_NetworkAdapter '
|
||||
'where Name = \'%(adapter_name_san)s\'' % locals())
|
||||
'where Name = \'%(adapter_name_san)s\'' % locals())
|
||||
if not len(q):
|
||||
raise Exception("Network adapter not found")
|
||||
|
||||
@ -260,7 +263,7 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
|
||||
def set_config_value(self, name, value):
|
||||
with _winreg.CreateKey(_winreg.HKEY_LOCAL_MACHINE,
|
||||
self._config_key) as key:
|
||||
self._config_key) as key:
|
||||
if type(value) == int:
|
||||
regtype = _winreg.REG_DWORD
|
||||
else:
|
||||
@ -270,7 +273,7 @@ class WindowsUtils(base.BaseOSUtils):
|
||||
def get_config_value(self, name):
|
||||
try:
|
||||
with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
|
||||
self._config_key) as key:
|
||||
self._config_key) as key:
|
||||
(value, regtype) = _winreg.QueryValueEx(key, name)
|
||||
return value
|
||||
except WindowsError:
|
||||
|
@ -14,6 +14,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class BasePlugin(object):
|
||||
def execute(self, service):
|
||||
pass
|
||||
|
@ -18,17 +18,19 @@ from cloudbaseinit.openstack.common import cfg
|
||||
from cloudbaseinit.utils import classloader
|
||||
|
||||
opts = [
|
||||
cfg.ListOpt('plugins', default=[
|
||||
cfg.ListOpt(
|
||||
'plugins',
|
||||
default=[
|
||||
'cloudbaseinit.plugins.windows.sethostname.SetHostNamePlugin',
|
||||
'cloudbaseinit.plugins.windows.createuser.CreateUserPlugin',
|
||||
'cloudbaseinit.plugins.windows.networkconfig.NetworkConfigPlugin',
|
||||
'cloudbaseinit.plugins.windows.sshpublickeys.'
|
||||
'SetUserSSHPublicKeysPlugin',
|
||||
'SetUserSSHPublicKeysPlugin',
|
||||
'cloudbaseinit.plugins.windows.userdata.UserDataPlugin'
|
||||
],
|
||||
help='List of enabled plugin classes, '
|
||||
'to executed in the provided order'),
|
||||
]
|
||||
'to executed in the provided order'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(opts)
|
||||
|
@ -25,15 +25,15 @@ from cloudbaseinit.plugins import base
|
||||
from cloudbaseinit.utils import crypt
|
||||
|
||||
opts = [
|
||||
cfg.StrOpt('username', default='Admin',
|
||||
help='User to be added to the system or updated if already existing'),
|
||||
cfg.ListOpt('groups', default=['Administrators'],
|
||||
help='List of local groups to which the user specified '
|
||||
'in \'username\' will be added'),
|
||||
cfg.BoolOpt('inject_user_password', default=True,
|
||||
help='Set the password provided in the configuration. '
|
||||
'If False or no password is provided, a random one will be set'),
|
||||
]
|
||||
cfg.StrOpt('username', default='Admin', help='User to be added to the '
|
||||
'system or updated if already existing'),
|
||||
cfg.ListOpt('groups', default=['Administrators'], help='List of local '
|
||||
'groups to which the user specified in \'username\' will '
|
||||
'be added'),
|
||||
cfg.BoolOpt('inject_user_password', default=True, help='Set the password '
|
||||
'provided in the configuration. If False or no password is '
|
||||
'provided, a random one will be set'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(opts)
|
||||
|
@ -18,22 +18,22 @@ import re
|
||||
|
||||
from cloudbaseinit.openstack.common import cfg
|
||||
from cloudbaseinit.openstack.common import log as logging
|
||||
from cloudbaseinit.osutils.factory import *
|
||||
from cloudbaseinit.plugins.base import *
|
||||
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'),
|
||||
]
|
||||
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():
|
||||
class NetworkConfigPlugin(base.BasePlugin):
|
||||
def execute(self, service):
|
||||
meta_data = service.get_meta_data('openstack')
|
||||
if 'network_config' not in meta_data:
|
||||
@ -50,11 +50,12 @@ class NetworkConfigPlugin():
|
||||
|
||||
# TODO (alexpilotti): implement a proper grammar
|
||||
m = re.search(r'iface eth0 inet static\s+'
|
||||
'address\s+(?P<address>[^\s]+)\s+'
|
||||
'netmask\s+(?P<netmask>[^\s]+)\s+'
|
||||
'broadcast\s+(?P<broadcast>[^\s]+)\s+'
|
||||
'gateway\s+(?P<gateway>[^\s]+)\s+'
|
||||
'dns\-nameservers\s+(?P<dnsnameservers>[^\r\n]+)\s+', debian_network_conf)
|
||||
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")
|
||||
|
||||
@ -64,7 +65,7 @@ class NetworkConfigPlugin():
|
||||
gateway = m.group('gateway')
|
||||
dnsnameservers = m.group('dnsnameservers').strip().split(' ')
|
||||
|
||||
osutils = OSUtilsFactory().get_os_utils()
|
||||
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
|
||||
|
||||
network_adapter_name = CONF.network_adapter
|
||||
if not network_adapter_name:
|
||||
|
@ -14,22 +14,21 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from cloudbaseinit.osutils.factory import *
|
||||
from cloudbaseinit.plugins.base import *
|
||||
from cloudbaseinit.osutils import factory as osutils_factory
|
||||
from cloudbaseinit.plugins import base
|
||||
from cloudbaseinit.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SetHostNamePlugin(BasePlugin):
|
||||
class SetHostNamePlugin(base.BasePlugin):
|
||||
def execute(self, service):
|
||||
meta_data = service.get_meta_data('openstack')
|
||||
if 'hostname' not in meta_data:
|
||||
LOG.debug('Hostname not found in metadata')
|
||||
return False
|
||||
|
||||
osutils = OSUtilsFactory().get_os_utils()
|
||||
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
|
||||
|
||||
new_host_name = meta_data['hostname'].split('.', 1)[0]
|
||||
return osutils.set_host_name(new_host_name)
|
||||
|
||||
|
@ -18,14 +18,14 @@ import os
|
||||
|
||||
from cloudbaseinit.openstack.common import cfg
|
||||
from cloudbaseinit.openstack.common import log as logging
|
||||
from cloudbaseinit.osutils.factory import *
|
||||
from cloudbaseinit.plugins.base import *
|
||||
from cloudbaseinit.osutils import factory as osutils_factory
|
||||
from cloudbaseinit.plugins import base
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SetUserSSHPublicKeysPlugin(BasePlugin):
|
||||
class SetUserSSHPublicKeysPlugin(base.BasePlugin):
|
||||
def execute(self, service):
|
||||
meta_data = service.get_meta_data('openstack')
|
||||
if not 'public_keys' in meta_data:
|
||||
@ -33,7 +33,7 @@ class SetUserSSHPublicKeysPlugin(BasePlugin):
|
||||
|
||||
username = CONF.username
|
||||
|
||||
osutils = OSUtilsFactory().get_os_utils()
|
||||
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
|
||||
user_home = osutils.get_user_home(username)
|
||||
|
||||
if not user_home:
|
||||
|
@ -14,18 +14,19 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
from cloudbaseinit.openstack.common import log as logging
|
||||
from cloudbaseinit.osutils.factory import *
|
||||
from cloudbaseinit.plugins.base import *
|
||||
from cloudbaseinit.osutils import factory as osutils_factory
|
||||
from cloudbaseinit.plugins import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UserDataPlugin():
|
||||
class UserDataPlugin(base.BasePlugin):
|
||||
def execute(self, service):
|
||||
user_data = service.get_user_data('openstack')
|
||||
if not user_data:
|
||||
@ -33,7 +34,7 @@ class UserDataPlugin():
|
||||
|
||||
LOG.debug('User data content:\n%s' % user_data)
|
||||
|
||||
osutils = OSUtilsFactory().get_os_utils()
|
||||
osutils = osutils_factory.OSUtilsFactory().get_os_utils()
|
||||
|
||||
target_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4()))
|
||||
if re.search(r'^rem cmd\s', user_data, re.I):
|
||||
@ -63,10 +64,10 @@ class UserDataPlugin():
|
||||
LOG.debug('User_data stdout:\n%s' % out)
|
||||
LOG.debug('User_data stderr:\n%s' % err)
|
||||
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:
|
||||
if os.path.exists(target_path):
|
||||
os.remove(target_path)
|
||||
|
||||
return False
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
import sys
|
||||
|
||||
from cloudbaseinit import init
|
||||
from cloudbaseinit.openstack.common import cfg
|
||||
from cloudbaseinit.openstack.common import log as logging2
|
||||
from cloudbaseinit.init import *
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging2.getLogger(__name__)
|
||||
@ -28,7 +28,4 @@ def main():
|
||||
CONF(sys.argv[1:])
|
||||
logging2.setup('cloudbaseinit')
|
||||
|
||||
init = InitManager()
|
||||
init.configure_host()
|
||||
|
||||
|
||||
init.InitManager().configure_host()
|
||||
|
@ -28,6 +28,7 @@ else:
|
||||
openssl = ctypes.CDLL(openssl_lib_path)
|
||||
clib = ctypes.CDLL(ctypes.util.find_library("c"))
|
||||
|
||||
|
||||
class RSA(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("pad", ctypes.c_int),
|
||||
|
46
setup.py
46
setup.py
@ -22,26 +22,26 @@ requires = common_setup.parse_requirements()
|
||||
dependency_links = common_setup.parse_dependency_links()
|
||||
|
||||
setuptools.setup(name='cloudbase-init',
|
||||
version='0.9.0',
|
||||
description='Portable cloud initialization service',
|
||||
author='Cloudbase Solutions Srl',
|
||||
author_email='apilotti@cloudbasesolutions.com',
|
||||
url='http://www.cloudbase.it/',
|
||||
classifiers=[
|
||||
'Environment :: OpenStack',
|
||||
'Intended Audience :: Information Technology',
|
||||
'Intended Audience :: System Administrators',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
],
|
||||
cmdclass=common_setup.get_cmdclass(),
|
||||
packages=setuptools.find_packages(exclude=['bin']),
|
||||
install_requires=requires,
|
||||
dependency_links=dependency_links,
|
||||
include_package_data=True,
|
||||
setup_requires=['setuptools_git>=0.4'],
|
||||
entry_points={'console_scripts': ['cloudbase-init = cloudbaseinit.shell:main']},
|
||||
py_modules=[])
|
||||
version='0.9.0',
|
||||
description='Portable cloud initialization service',
|
||||
author='Cloudbase Solutions Srl',
|
||||
author_email='apilotti@cloudbasesolutions.com',
|
||||
url='http://www.cloudbase.it/',
|
||||
classifiers=['Environment :: OpenStack',
|
||||
'Intended Audience :: Information Technology',
|
||||
'Intended Audience :: System Administrators',
|
||||
'License :: OSI Approved :: Apache Software '
|
||||
'License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7'],
|
||||
cmdclass=common_setup.get_cmdclass(),
|
||||
packages=setuptools.find_packages(exclude=['bin']),
|
||||
install_requires=requires,
|
||||
dependency_links=dependency_links,
|
||||
include_package_data=True,
|
||||
setup_requires=['setuptools_git>=0.4'],
|
||||
entry_points={'console_scripts':
|
||||
['cloudbase-init = cloudbaseinit.shell:main']},
|
||||
py_modules=[])
|
||||
|
Loading…
Reference in New Issue
Block a user