[CRIU] [PATCH 2/7] pycriu: add python package, v3

Ruslan Kuprieiev kupruser at gmail.com
Tue Dec 2 06:05:26 PST 2014


On 12/02/2014 03:04 PM, Pavel Emelyanov wrote:
>> diff --git a/pycriu/.gitignore b/pycriu/.gitignore
>> new file mode 100644
>> index 0000000..8d503da
>> --- /dev/null
>> +++ b/pycriu/.gitignore
>> @@ -0,0 +1,3 @@
>> +*_pb2.py
>> +*.pyc
>> +rpc.py
>> diff --git a/pycriu/Makefile b/pycriu/Makefile
>> new file mode 100644
>> index 0000000..135fe1c
>> --- /dev/null
>> +++ b/pycriu/Makefile
>> @@ -0,0 +1,16 @@
>> +all: images rpc.py
>> +
>> +.PHONY: all images clean
>> +
>> +images:
>> +	$(Q) $(MAKE) -C images all
>> +
>> +# rpc_pb2.py doesn't depend on any other file, so
>> +# it is safe to rename it, dropping ugly _pb2 suffix.
>> +rpc.py:
>> +	$(Q) protoc -I=$(SRC_DIR)/protobuf/ --python_out=./ $(SRC_DIR)/protobuf/$(@:.py=.proto)
>> +	$(Q) mv $(@:.py=_pb2.py) $@
>
> Why do we need rpc.py?

Because it is handy to have all pythonic criu stuff in one
package called pycriu.

>
>> +clean:
>> +	$(Q) $(MAKE) -C images clean
>> +	$(Q) $(RM) rpc.py *.pyc
>> diff --git a/pycriu/__init__.py b/pycriu/__init__.py
>> new file mode 100644
>> index 0000000..5205973
>> --- /dev/null
>> +++ b/pycriu/__init__.py
>> @@ -0,0 +1,2 @@
>> +import rpc
>> +import images
>> diff --git a/pycriu/images/.gitignore b/pycriu/images/.gitignore
>> new file mode 100644
>> index 0000000..234bfe9
>> --- /dev/null
>> +++ b/pycriu/images/.gitignore
>> @@ -0,0 +1,4 @@
>> +*.pyc
>> +*_pb2.py
>> +magic.py
>> +pb.py
>> diff --git a/pycriu/images/Makefile b/pycriu/images/Makefile
>> new file mode 100644
>> index 0000000..6aa115e
>> --- /dev/null
>> +++ b/pycriu/images/Makefile
>> @@ -0,0 +1,26 @@
>> +all: pb.py protobuf magic.py
>> +
>> +.PHONY: all protobuf clean pb.py
>> +
>> +proto := $(filter-out $(SRC_DIR)/protobuf/rpc.proto, $(wildcard $(SRC_DIR)/protobuf/*.proto))
>> +proto-py-modules := $(foreach m,$(proto),$(subst -,_,$(notdir $(m:.proto=_pb2))))
>> +
>> +# We don't need rpc_pb2.py here, as it is not related to the
>> +# images.
>> +# Unfortunately, we can't drop ugly _pb2 suffixes here, because
>> +# some _pb2 files depend on others _pb2 files.
>> +protobuf:
>> +	$(Q) protoc -I=$(SRC_DIR)/protobuf --python_out=./ $(proto)
>> +
>> +magic.py: $(SRC_DIR)/scripts/magic-gen.py $(SRC_DIR)/include/magic.h
>> +	$(E) "  GEN  " $@
>> +	$(Q) python $^ $@
>> +
>> +pb.py: protobuf
>> +	$(Q) echo "# Autogenerated. Do not edit!" > $@
>> +	$(Q) for m in $(proto-py-modules); do \
>> +		echo "from $$m import *" >> $@ ;\
>> +	done
>> +
>> +clean:
>> +	$(Q) $(RM) ./*_pb2.py ./*.pyc magic.py pb.py
>> diff --git a/pycriu/images/__init__.py b/pycriu/images/__init__.py
>> new file mode 100644
>> index 0000000..379943b
>> --- /dev/null
>> +++ b/pycriu/images/__init__.py
>> @@ -0,0 +1,3 @@
>> +from magic import *
>> +from images import *
>> +from pb import *
>> diff --git a/pycriu/images/images.py b/pycriu/images/images.py
>> new file mode 100644
>> index 0000000..afcaa87
>> --- /dev/null
>> +++ b/pycriu/images/images.py
>> @@ -0,0 +1,208 @@
>> +#!/bin/env python
>> +import io
>> +import google
>> +import struct
>> +import os
>> +import sys
>> +
>> +from magic import *
>> +from pb import *
>> +
>> +class _cr_desc:
>> +	def __init__(self, magic, head, body='', single=False):
>
> I'm not sure the single bit is needed. But what's needed is some
> sign that image may have raw data inside. For example:
>
> # ../crit convert --in dump/static/pipe00/6596/1/pipes-data.img
> Traceback (most recent call last):
>    ...
>    File "/usr/lib/python2.7/site-packages/google/protobuf/internal/decoder.py", line 685, in _RaiseInvalidWireType
>      raise _DecodeError('Tag had invalid wire type.')
> google.protobuf.message.DecodeError: Tag had invalid wire type.
>
> That's because crit tries todecode raw pipe data as message.
>

Not sure about single bit, but will try to optimize it.
Yes, you are right about raw data. Will fix.

>> +		self.magic_name = magic
>> +		self.magic = eval(magic+"_MAGIC")
>> +		self.head_name = head
>> +		self.head = eval(head)
>> +		if single:
>> +			self.body_name = ''
>> +			self.body = lambda : None
>> +		else:
>> +			if body == '':
>> +				body = head
>> +			self.body_name = body
>> +			self.body = eval(body)
>> +
>> +class criu_image_descs:
> ...
>> +
>> +	def get(self, magic):
>> +		desc = None
>> +		for d in self.descs:
>> +			if d.magic == magic or d.magic_name == magic:
>> +				desc = d
>> +				break
>
> Can we utilize python power to search objects in lists/hashes/sets
> and not do it by hands?
>

I guess we can.

>> +		if desc == None:
>> +			raise Exception("Unknown magic")
>> +		else:
>> +			return desc
>> +
>> +class criu_image:
>> +	def __init__(self):
>> +		self.desc	= None
>> +		self.msgs	= []
>> +		self.orig_type	= None
>> +
>> +	def ParseFromStringIMG(self, s):
>> +		s = io.BytesIO(s)
>> +		magic, = struct.unpack('i', s.read(4))
>> +		magic = "0x{0:x}".format(magic)
>> +
>> +		descs = criu_image_descs()
>> +		try:
>> +			self.desc = descs.get(magic)
>> +		except Exception as e:
>> +			raise e
>> +
>> +		pb = self.desc.head()
>> +		while pb != None:
>> +			buf = s.read(4)
>> +			if buf == '':
>> +				break
>> +			size, = struct.unpack('i', buf)
>> +			pb.ParseFromString(s.read(size))
>> +			self.msgs.append(pb)
>> +			pb = self.desc.body()
>> +
>> +	def ParseFromStringTXT(self, s):
>> +		s = io.BytesIO(s)
>> +		magic = (s.readline())[1:-1]
>> +
>> +		descs = criu_image_descs()
>> +		try:
>> +			self.desc = descs.get(magic)
>> +		except Exception as e:
>> +			raise e
>> +
>> +		pb = self.desc.head()
>> +		while pb != None:
>> +			buf = s.readline()
>> +			if buf == '':
>> +				break
>> +			if buf[0] != '#':
>> +				raise Exception('# expected')
>> +			pb_text = ''
>> +			while True:
>> +				buf = s.readline()
>> +				if buf == '':
>> +					break
>> +				if buf[0] == '#':
>> +					s.seek(-len(buf), 1)
>> +					break
>> +				elif buf[0] == '':
>> +					raise Exception("data expected")
>> +				else:
>> +					pb_text += buf
>> +			google.protobuf.text_format.Merge(pb_text, pb)
>> +			self.msgs.append(pb)
>> +			pb = self.desc.body()
>> +
>> +	def ParseFromString(self, s):
>
> Let's make this call be ParseFromFile and pass here not
> sting, but an object from which we can read().
>

It might be useful to have both ParseFromString and ParseFromFile.
I'll take a look.

>> +		if s[0] == '#':
>> +			self.orig_type = 'txt'
>> +			self.ParseFromStringTXT(s)
>> +		else:
>> +			self.orig_type = 'img'
>> +			self.ParseFromStringIMG(s)
>> +
>> +	def SerializeToStringIMG(self):
>> +		s = io.BytesIO('')
>> +		s.write(struct.pack('i', int(self.desc.magic, 16)))
>> +
>> +		for pb in self.msgs:
>> +			pb_str = pb.SerializeToString()
>> +			size = len(pb_str)
>> +			s.write(struct.pack('i', size))
>> +			s.write(pb_str)
>> +		s.seek(0)
>
> Why?
>

Yeah, it is ugly =). I'll fix it.
Thanks.

>> +		return s.read()
>> +
>> +	def SerializeToStringTXT(self, nice=False):
>> +		s = io.BytesIO('')
>> +
>> +		if nice:
>> +			magic = self.desc.magic_name
>> +			indent = 4
>> +		else:
>> +			magic = self.desc.magic
>> +			indent = 0
>> +
>> +		s.write('#'+magic+'\n')
>> +
>> +		index = 0
>> +		for pb in self.msgs:
>> +			if nice:
>> +				if index == 0:
>> +					pb_name = self.desc.head_name
>> +				else:
>> +					pb_name = self.desc.body_name
>> +			else:
>> +				pb_name = ''
>> +
>> +			s.write('#'+str(index)+' '+pb_name+'\n')
>> +			google.protobuf.text_format.PrintMessage(pb, s, indent=indent)
>> +			index += 1
>> +		s.seek(0)
>> +		return s.read()
>> +
>> +	def SerializeToString(self, nice=False):
>> +		if self.orig_type == 'img':
>> +			return self.SerializeToStringTXT(nice=nice)
>> +		else:
>> +			return self.SerializeToStringIMG()
>>
>



More information about the CRIU mailing list