Exemplo n.º 1
0
	def _create(self, volume, snapshot, snap_lv, tranzit_path,  complete_cb):
		try:
			chunk_prefix = '%s.data' % snapshot.id
			snapshot.path = None
			snap_mpoint = mkdtemp()
			try:
				opts = []
				if volume.fstype == 'xfs':
					opts += ['-o', 'nouuid,ro']
				mount(snap_lv, snap_mpoint, opts)				
				tar_cmd = ['tar', 'cp', '-C', snap_mpoint, '.']
				
				pigz_bins = whereis('pigz')
				compress_cmd = [pigz_bins[0] if pigz_bins else 'gzip', '-5'] 
				
				self._logger.debug("Creating and compressing snapshot data.")
				tar = subprocess.Popen(tar_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
				compress = subprocess.Popen(compress_cmd, stdin=tar.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
				tar.stdout.close() # Allow tar to receive a SIGPIPE if compress exits.
				split = threading.Thread(target=self._split, name='split', 
						  args=(compress.stdout, tranzit_path, chunk_prefix, snapshot))
				split.start()
								
				uploaders = []
				for i in range(2):
					uploader = threading.Thread(name="Uploader-%s" % i, target=self._uploader, 
											  args=(volume.snap_backend['path'], snapshot))
					self._logger.debug("Starting uploader '%s'", uploader.getName())
					
					uploader.start()
					uploaders.append(uploader)
				self._logger.debug('uploaders started. waiting compress')

				compress.wait()
				self._logger.debug('compress completed (code: %s). waiting split', compress.returncode)
				if compress.returncode:
					raise StorageError('Compress process terminated with exit code %s. <err>: %s' % (compress.returncode, compress.stderr.read()))				
					
				split.join()
				self._logger.debug('split completed. waiting uploaders')

				for uploader in uploaders:
					uploader.join()
				self._logger.debug('uploaders completed')
				
				if self._inner_exc_info:
					t, e, s = self._inner_exc_info
					raise t, e, s

			finally:
				self._return_ev.set()				
				umount(snap_mpoint, options=('-f',))
				os.rmdir(snap_mpoint)
				self._lvm.remove_lv(snap_lv)
				self._inner_exc_info = None
			self._state_map[snapshot.id] = Snapshot.COMPLETED
		except (Exception, BaseException), e:
			self._state_map[snapshot.id] = Snapshot.FAILED
			self._logger.exception('Snapshot creation failed. %s' % e)
Exemplo n.º 2
0
	def on_init(self, *args, **kwargs):
		bus.on("before_hello", self.on_before_hello)		
		bus.on("before_host_init", self.on_before_host_init)
		bus.on("before_restart", self.on_before_restart)

		msg_service = bus.messaging_service
		producer = msg_service.get_producer()
		producer.on("before_send", self.on_before_message_send)
		
		# Set the hostname to this instance's public hostname
		cnf = bus.cnf
		try:
			hostname_as_pubdns = int(cnf.rawini.get('ec2', 'hostname_as_pubdns'))
		except ConfigParser.Error:
			hostname_as_pubdns = True
		if hostname_as_pubdns:
			system2("hostname " + self._platform.get_public_hostname(), shell=True)		
		
		if disttool.is_ubuntu():
			# Ubuntu cloud-init scripts may disable root ssh login
			for path in ('/etc/ec2-init/ec2-config.cfg', '/etc/cloud/cloud.cfg'):
				if os.path.exists(path):
					c = filetool.read_file(path)
					c = re.sub(re.compile(r'^disable_root[^:=]*([:=]).*', re.M), r'disable_root\1 0', c)
					filetool.write_file(path, c)
			
		# Add server ssh public key to authorized_keys
		authorized_keys_path = "/root/.ssh/authorized_keys"
		if os.path.exists(authorized_keys_path):
			c = filetool.read_file(authorized_keys_path)
			ssh_key = self._platform.get_ssh_pub_key()
			idx = c.find(ssh_key)
			if idx == -1:
				if c and c[-1] != '\n':
					c += '\n'
				c += ssh_key + "\n"
				self._logger.debug("Add server ssh public key to authorized_keys")
				filetool.write_file(authorized_keys_path, c)
			elif idx > 0 and c[idx-1] != '\n':
				c = c[0:idx] + '\n' + c[idx:]
				self._logger.warn('Adding new-line character before server SSH key in authorized_keys file')
				filetool.write_file(authorized_keys_path, c)
				
		# Mount ephemeral devices
		# Seen on eucalyptus: 
		# 	- fstab contains invalid fstype and `mount -a` fails  
		mtab = Mtab()
		fstab = Fstab()
		for device in self._platform.instance_store_devices:
			if os.path.exists(device) and fstab.contains(device) and not mtab.contains(device):
				entry = fstab.find(device)[0]
				try:
					mount(device, entry.mpoint, ('-o', entry.options))
				except:
					self._logger.warn(sys.exc_info()[1])
Exemplo n.º 3
0
	def _create_attach_mount_volume(self, size=None, auto_mount=False, snapshot=None, mpoint=None, mkfs=True):
		pl = cassandra.platform
		ec2_conn = pl.new_ec2_conn()
		
		# Create volume
		vol = ebstool.create_volume(ec2_conn, size, 
				pl.get_avail_zone(), snapshot, self._logger)
		
		# Attach 
		devname = get_free_devname()
		devname = ebstool.attach_volume(ec2_conn, 
									vol, pl.get_instance_id(), devname, 
									to_me=True, logger=self._logger)[1]
		
		# Mount
		fstool.mount(devname, mpoint, make_fs=mkfs, auto_mount=auto_mount)		
		
		del(ec2_conn)
		return devname, vol
Exemplo n.º 4
0
	def post_handle_request(self):
		if self.umounted:
			fstool.mount(self.device_name, cassandra.storage_path)
		cassandra.start_service()
Exemplo n.º 5
0
	def _mount_image(self, options=None):
		LOG.info("Mounting image")
		if self._mtab.contains(mpoint=self.mpoint):
			raise HandlerError("Image already mounted")
		fstool.mount(self.devname, self.mpoint, options)
Exemplo n.º 6
0
	def rebundle(self):
		rebundle_dir = tempfile.mkdtemp()

		try:
			pl = bus.platform
			proj_id = pl.get_numeric_project_id()
			proj_name = pl.get_project_id()
			cloudstorage = pl.new_storage_client()

			tmp_mount_dir = os.path.join(rebundle_dir, 'root')
			os.makedirs(tmp_mount_dir)

			image_name	= 'disk.raw'
			image_path	= os.path.join(rebundle_dir, image_name)

			root = filter(lambda x: x.mpoint == '/', filetool.df())[0]

			LOG.debug('Creating image file %s' % image_path)
			with open(image_path, 'w') as f:
				f.truncate(root.size*1024 + 1*1024)

			try:

				LOG.debug('Creating partition table on image')
				system2(('parted', image_path, 'mklabel', 'msdos'))
				system2(('parted', image_path, 'mkpart', 'primary', 'ext2', 1, str(root.size/1024)))

				# Map disk image
				out = system2(('kpartx', '-av', image_path))[0]
				try:
					loop = re.search('(/dev/loop\d+)', out).group(1)
					root_dev_name = '/dev/mapper/%sp1' % loop.split('/')[-1]

					LOG.info('Creating filesystem')
					fstool.mkfs(root_dev_name, 'ext4')
					dev_uuid = uuid.uuid4()
					system2(('tune2fs', '-U', str(dev_uuid), root_dev_name))

					fstool.mount(root_dev_name, tmp_mount_dir)
					try:
						lines = system2(('/bin/mount', '-l'))[0].splitlines()
						exclude_dirs = set()
						for line in lines:
							mpoint = line.split()[2]
							if mpoint != '/':
								exclude_dirs.add(mpoint)

						exclude_dirs.update(self.exclude_dirs)

						rsync = filetool.Rsync()
						rsync.source('/').dest(tmp_mount_dir).sparse()
						rsync.hardlinks().archive().times()
						rsync.exclude([os.path.join(ex, '**') for ex in exclude_dirs])
						rsync.exclude(self.exclude_files)
						rsync.exclude(self._excludes)
						LOG.info('Copying root filesystem to image')
						rsync.execute()

						LOG.info('Cleanup image')
						self._create_spec_devices(tmp_mount_dir)

						LOG.debug('Removing roles-builder user')
						sh = pexpect.spawn('/bin/sh')
						try:
							sh.sendline('chroot %s' % tmp_mount_dir)
							sh.expect('#')
							sh.sendline('userdel -rf %s' % ROLEBUILDER_USER)
							sh.expect('#')
						finally:
							sh.close()

						""" Patch fstab"""
						fstab_path = os.path.join(tmp_mount_dir, 'etc/fstab')
						if os.path.exists(fstab_path):
							with open(fstab_path) as f:
								fstab = f.read()

							new_fstab = re.sub('UUID=\S+\s+/\s+(.*)', 'UUID=%s / \\1' % dev_uuid, fstab)

							with open(fstab_path, 'w') as f:
								f.write(new_fstab)

					finally:
						fstool.umount(device=root_dev_name)
				finally:
					system2(('kpartx', '-d', image_path))

				LOG.info('Compressing image.')
				arch_name = '%s.tar.gz' % self._role_name.lower()
				arch_path = os.path.join(rebundle_dir, arch_name)

				tar = filetool.Tar()
				tar.create().gzip().sparse()
				tar.archive(arch_path)
				tar.add(image_name, rebundle_dir)
				system2(str(tar), shell=True)

			finally:
				os.unlink(image_path)

			try:
				LOG.info('Uploading compressed image to cloud storage')
				uploader = transfer.Transfer(logger=LOG)
				tmp_bucket_name = 'scalr-images-%s-%s' % (
									random.randint(1,1000000), int(time.time()))

				try:
					remote_path = 'gcs://%s/' % tmp_bucket_name
					uploader.upload((arch_path,), remote_path)
				except:
					try:
						objs = cloudstorage.objects()
						objs.delete(bucket=tmp_bucket_name, object=arch_name).execute()
					except:
						pass

					cloudstorage.buckets().delete(bucket=tmp_bucket_name).execute()
					raise

			finally:
				os.unlink(arch_path)

		finally:
			shutil.rmtree(rebundle_dir)

		try:
			goog_image_name = self._role_name.lower().replace('_', '-')
			LOG.info('Registering new image %s' % goog_image_name)
			# TODO: check duplicate names
			compute = pl.new_compute_client()

			image_url = 'http://storage.googleapis.com/%s/%s' % (
											tmp_bucket_name, arch_name)
			req_body = dict(
				name=goog_image_name,
				sourceType='RAW',
				rawDisk=dict(
					containerType='TAR',
					source=image_url
				)
			)

			req = compute.images().insert(project=proj_id, body=req_body)
			operation = req.execute()['name']

			LOG.info('Waiting for image to register')
			def image_is_ready():
				req = compute.operations().get(project=proj_id, operation=operation)
				res = req.execute()
				if res['status'] == 'DONE':
					if res.get('error'):
						errors = []
						for e in res['error']['errors']:
							err_text = '%s: %s' % (e['code'], e['message'])
							errors.append(err_text)
						raise Exception('\n'.join(errors))
					return True
				return False
			wait_until(image_is_ready, logger=LOG, timeout=600)

		finally:
			objs = cloudstorage.objects()
			objs.delete(bucket=tmp_bucket_name, object=arch_name).execute()
			cloudstorage.buckets().delete(bucket=tmp_bucket_name).execute()

		return '%s/images/%s' % (proj_name, goog_image_name)