241 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| Installs and configures an OpenStack Swift
 | |
| """
 | |
| 
 | |
| import uuid
 | |
| import logging
 | |
| import os
 | |
| 
 | |
| import packstack.installer.engine_validators as validate
 | |
| import packstack.installer.engine_processors as process
 | |
| from packstack.installer import basedefs
 | |
| import packstack.installer.common_utils as utils
 | |
| 
 | |
| from packstack.modules.ospluginutils import getManifestTemplate, appendManifestFile, manifestfiles
 | |
| 
 | |
| # Controller object will be initialized from main flow
 | |
| controller = None
 | |
| 
 | |
| # Plugin name
 | |
| PLUGIN_NAME = "OS-SWIFT"
 | |
| PLUGIN_NAME_COLORED = utils.getColoredText(PLUGIN_NAME, basedefs.BLUE)
 | |
| 
 | |
| logging.debug("plugin %s loaded", __name__)
 | |
| 
 | |
| def initConfig(controllerObject):
 | |
|     global controller
 | |
|     controller = controllerObject
 | |
|     logging.debug("Adding OpenStack Swift configuration")
 | |
|     paramsList = [
 | |
|                   {"CMD_OPTION"      : "os-swift-proxy",
 | |
|                    "USAGE"           : "The IP address on which to install the Swift proxy service",
 | |
|                    "PROMPT"          : "Enter the IP address of the Swift proxy service",
 | |
|                    "OPTION_LIST"     : [],
 | |
|                    "VALIDATORS"      : [validate.validate_ip, validate.validate_ssh],
 | |
|                    "DEFAULT_VALUE"   : utils.getLocalhostIP(),
 | |
|                    "MASK_INPUT"      : False,
 | |
|                    "LOOSE_VALIDATION": True,
 | |
|                    "CONF_NAME"       : "CONFIG_SWIFT_PROXY_HOSTS", #XXX: Shouldn't be here CONFIG_SWIFT_PROXY_HOST?
 | |
|                    "USE_DEFAULT"     : False,
 | |
|                    "NEED_CONFIRM"    : False,
 | |
|                    "CONDITION"       : False },
 | |
|                   {"CMD_OPTION"      : "os-swift-ks-passwd",
 | |
|                    "USAGE"           : "The password to use for the Swift to authenticate with Keystone",
 | |
|                    "PROMPT"          : "Enter the password for the Swift Keystone access",
 | |
|                    "OPTION_LIST"     : [],
 | |
|                    "VALIDATORS"      : [validate.validate_not_empty],
 | |
|                    "DEFAULT_VALUE"   : uuid.uuid4().hex[:16],
 | |
|                    "MASK_INPUT"      : True,
 | |
|                    "LOOSE_VALIDATION": False,
 | |
|                    "CONF_NAME"       : "CONFIG_SWIFT_KS_PW",
 | |
|                    "USE_DEFAULT"     : True,
 | |
|                    "NEED_CONFIRM"    : True,
 | |
|                    "CONDITION"       : False },
 | |
|                   {"CMD_OPTION"      : "os-swift-storage",
 | |
|                    "USAGE"           : "A comma separated list of IP addresses on which to install the Swift Storage services, each entry should take the format <ipaddress>[/dev], for example 127.0.0.1/vdb will install /dev/vdb on 127.0.0.1 as a swift storage device(packstack does not create the filesystem, you must first do this first), if /dev is omitted Packstack will create a loopback device for a test setup",
 | |
|                    "PROMPT"          : "Enter the Swift Storage servers e.g. host/dev,host/dev",
 | |
|                    "OPTION_LIST"     : [],
 | |
|                    "VALIDATORS"      : [validate.validate_not_empty, validate_storage],
 | |
|                    "DEFAULT_VALUE"   : utils.getLocalhostIP(),
 | |
|                    "MASK_INPUT"      : False,
 | |
|                    "LOOSE_VALIDATION": True,
 | |
|                    "CONF_NAME"       : "CONFIG_SWIFT_STORAGE_HOSTS",
 | |
|                    "USE_DEFAULT"     : False,
 | |
|                    "NEED_CONFIRM"    : False,
 | |
|                    "CONDITION"       : False },
 | |
|                   {"CMD_OPTION"      : "os-swift-storage-zones",
 | |
|                    "USAGE"           : "Number of swift storage zones, this number MUST be no bigger than the number of storage devices configured",
 | |
|                    "PROMPT"          : "Enter the number of swift storage zones, MUST be no bigger than the number of storage devices configured",
 | |
|                    "OPTION_LIST"     : [],
 | |
|                    "VALIDATORS"      : [validate.validate_integer],
 | |
|                    "DEFAULT_VALUE"   : "1",
 | |
|                    "MASK_INPUT"      : False,
 | |
|                    "LOOSE_VALIDATION": True,
 | |
|                    "CONF_NAME"       : "CONFIG_SWIFT_STORAGE_ZONES",
 | |
|                    "USE_DEFAULT"     : False,
 | |
|                    "NEED_CONFIRM"    : False,
 | |
|                    "CONDITION"       : False },
 | |
|                   {"CMD_OPTION"      : "os-swift-storage-replicas",
 | |
|                    "USAGE"           : "Number of swift storage replicas, this number MUST be no bigger than the number of storage zones configured",
 | |
|                    "PROMPT"          : "Enter the number of swift storage replicas, MUST be no bigger than the number of storage zones configured",
 | |
|                    "OPTION_LIST"     : [],
 | |
|                    "VALIDATORS"      : [validate.validate_integer],
 | |
|                    "DEFAULT_VALUE"   : "1",
 | |
|                    "MASK_INPUT"      : False,
 | |
|                    "LOOSE_VALIDATION": True,
 | |
|                    "CONF_NAME"       : "CONFIG_SWIFT_STORAGE_REPLICAS",
 | |
|                    "USE_DEFAULT"     : False,
 | |
|                    "NEED_CONFIRM"    : False,
 | |
|                    "CONDITION"       : False },
 | |
|                   {"CMD_OPTION"      : "os-swift-storage-fstype",
 | |
|                    "USAGE"           : "FileSystem type for storage nodes",
 | |
|                    "PROMPT"          : "Enter FileSystem type for storage nodes",
 | |
|                    "OPTION_LIST"     : ['xfs','ext4'],
 | |
|                    "VALIDATORS"      : [validate.validate_options],
 | |
|                    "DEFAULT_VALUE"   : "ext4",
 | |
|                    "MASK_INPUT"      : False,
 | |
|                    "LOOSE_VALIDATION": True,
 | |
|                    "CONF_NAME"       : "CONFIG_SWIFT_STORAGE_FSTYPE",
 | |
|                    "USE_DEFAULT"     : False,
 | |
|                    "NEED_CONFIRM"    : False,
 | |
|                    "CONDITION"       : False },
 | |
|                  ]
 | |
| 
 | |
|     groupDict = { "GROUP_NAME"            : "OSSWIFT",
 | |
|                   "DESCRIPTION"           : "OpenStack Swift Config parameters",
 | |
|                   "PRE_CONDITION"         : "CONFIG_SWIFT_INSTALL",
 | |
|                   "PRE_CONDITION_MATCH"   : "y",
 | |
|                   "POST_CONDITION"        : False,
 | |
|                   "POST_CONDITION_MATCH"  : True}
 | |
| 
 | |
|     controller.addGroup(groupDict, paramsList)
 | |
| 
 | |
| 
 | |
| def validate_storage(param, options=None):
 | |
|     for host in param.split(','):
 | |
|         host = host.split('/', 1)[0]
 | |
|         validate.validate_ip(host.strip(), options)
 | |
| 
 | |
| 
 | |
| def initSequences(controller):
 | |
|     if controller.CONF['CONFIG_SWIFT_INSTALL'] != 'y':
 | |
|         return
 | |
| 
 | |
|     steps = [
 | |
|              {'title': 'Adding Swift Keystone manifest entries', 'functions':[createkeystonemanifest]},
 | |
|              {'title': 'Adding Swift builder manifest entries', 'functions':[createbuildermanifest]},
 | |
|              {'title': 'Adding Swift proxy manifest entries', 'functions':[createproxymanifest]},
 | |
|              {'title': 'Adding Swift storage manifest entries', 'functions':[createstoragemanifest]},
 | |
|              {'title': 'Adding Swift common manifest entries', 'functions':[createcommonmanifest]},
 | |
|     ]
 | |
|     controller.addSequence("Installing OpenStack Swift", [], [], steps)
 | |
| 
 | |
| 
 | |
| def createkeystonemanifest():
 | |
|     manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST']
 | |
|     controller.CONF['CONFIG_SWIFT_PROXY'] = controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'].split(',')[0]
 | |
|     manifestdata = getManifestTemplate("keystone_swift.pp")
 | |
|     appendManifestFile(manifestfile, manifestdata)
 | |
| 
 | |
| 
 | |
| devices = []
 | |
| def parseDevices(config_swift_storage_hosts):
 | |
|     device_number = 0
 | |
|     for host in config_swift_storage_hosts.split(","):
 | |
|         device_number += 1
 | |
|         device = None
 | |
|         if '/' in host:
 | |
|             host, device = host.split('/')[0:2]
 | |
|         zone = (device_number % int(controller.CONF["CONFIG_SWIFT_STORAGE_ZONES"]))+1
 | |
|         devices.append({'host':host, 'device':device, 'device_name':'device%s'%device_number, 'zone':str(zone)})
 | |
|     return devices
 | |
| 
 | |
| 
 | |
| # The ring file should be built and distributed befor the storage services
 | |
| # come up. Specifically the replicator crashes if the ring isn't present
 | |
| def createbuildermanifest():
 | |
|     # TODO : put this on the proxy server, will need to change this later
 | |
|     controller.CONF['CONFIG_SWIFT_BUILDER_HOST'] = controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'].split(',')[0]
 | |
|     manifestfile = "%s_ring_swift.pp"%controller.CONF['CONFIG_SWIFT_BUILDER_HOST']
 | |
|     manifestdata = getManifestTemplate("swift_builder.pp")
 | |
| 
 | |
|     # Add each device to the ring
 | |
|     devicename = 0
 | |
|     for device in parseDevices(controller.CONF["CONFIG_SWIFT_STORAGE_HOSTS"]):
 | |
|         host = device['host']
 | |
|         devicename = device['device_name']
 | |
|         zone = device['zone']
 | |
| 
 | |
|         manifestdata = manifestdata + '\n@@ring_object_device { "%s:6000/%s":\n zone        => %s,\n weight      => 10, }'%(host, devicename, zone)
 | |
|         manifestdata = manifestdata + '\n@@ring_container_device { "%s:6001/%s":\n zone        => %s,\n weight      => 10, }'%(host, devicename, zone)
 | |
|         manifestdata = manifestdata + '\n@@ring_account_device { "%s:6002/%s":\n zone        => %s,\n weight      => 10, }'%(host, devicename, zone)
 | |
| 
 | |
|     appendManifestFile(manifestfile, manifestdata, 'swiftbuilder')
 | |
| 
 | |
| 
 | |
| def createproxymanifest():
 | |
|     manifestfile = "%s_swift.pp"%controller.CONF['CONFIG_SWIFT_PROXY_HOSTS']
 | |
|     manifestdata = getManifestTemplate("swift_proxy.pp")
 | |
|     # If the proxy server is also a storage server then swift::ringsync will be included for the storage server
 | |
|     if controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'] not in [h['host'] for h in devices]:
 | |
|         manifestdata += 'swift::ringsync{["account","container","object"]:\n    ring_server => "%s"\n}'%controller.CONF['CONFIG_SWIFT_BUILDER_HOST']
 | |
|     appendManifestFile(manifestfile, manifestdata)
 | |
| 
 | |
| 
 | |
| def check_device(host, device):
 | |
|     """
 | |
|     Raises ScriptRuntimeError if given device is not mounted on given
 | |
|     host.
 | |
|     """
 | |
|     server = utils.ScriptRunner()
 | |
| 
 | |
|     # the device MUST exist
 | |
|     cmd = 'ls -l /dev/%s'
 | |
|     server.append(cmd % device)
 | |
| 
 | |
|     # if it is not mounted then we can use it
 | |
|     cmd = 'grep "/dev/%s " /proc/self/mounts || exit 0'
 | |
|     server.append(cmd % device)
 | |
| 
 | |
|     # if it is mounted then the mount point has to be in /srv/node
 | |
|     cmd = 'grep "/dev/%s /srv/node" /proc/self/mounts && exit 0'
 | |
|     server.append(cmd % device)
 | |
| 
 | |
|     # if we got here without exiting then we can't use this device
 | |
|     server.append('exit 1')
 | |
|     server.execute()
 | |
|     return False
 | |
| 
 | |
| 
 | |
| def createstoragemanifest():
 | |
| 
 | |
|     # this need to happen once per storage host
 | |
|     for host in set([device['host'] for device in devices]):
 | |
|         controller.CONF["CONFIG_SWIFT_STORAGE_CURRENT"] = host
 | |
|         manifestfile = "%s_swift.pp"%host
 | |
|         manifestdata = getManifestTemplate("swift_storage.pp")
 | |
|         appendManifestFile(manifestfile, manifestdata)
 | |
| 
 | |
|     # this need to happen once per storage device
 | |
|     for device in devices:
 | |
|         host = device['host']
 | |
|         devicename = device['device_name']
 | |
|         device = device['device']
 | |
|         if device:
 | |
|             check_device(host, device)
 | |
| 
 | |
|         manifestfile = "%s_swift.pp"%host
 | |
|         if device:
 | |
|             manifestdata = "\n" + 'swift::storage::%s{"%s":\n  device => "/dev/%s",\n}'% (controller.CONF["CONFIG_SWIFT_STORAGE_FSTYPE"], devicename, device)
 | |
|         else:
 | |
|             controller.CONF["SWIFT_STORAGE_DEVICES"] = "'%s'"%devicename
 | |
|             manifestdata = "\n" + getManifestTemplate("swift_loopback.pp")
 | |
|         appendManifestFile(manifestfile, manifestdata)
 | |
| 
 | |
| 
 | |
| def createcommonmanifest():
 | |
|     for manifestfile, marker in manifestfiles.getFiles():
 | |
|         if manifestfile.endswith("_swift.pp"):
 | |
|             data = getManifestTemplate("swift_common.pp")
 | |
|             appendManifestFile(os.path.split(manifestfile)[1], data)
 | 
