To avoid retinal burn from emacs show-trailing-whitespace highlighting
and constant spanking from git's trailing-space warnings.
---
imagefactory/BuildDispatcher.py | 21 ++--
imagefactory/ImageWarehouse.py | 107 +++++++++---------
imagefactory/Template.py | 37 +++---
imagefactory/builders/BaseBuilder.py | 51 ++++----
imagefactory/builders/FedoraBuilder.py | 172 ++++++++++++++--------------
imagefactory/builders/IBuilder.py | 9 +-
imagefactory/builders/IBuilderDelegate.py | 15 +--
imagefactory/builders/MockBuilder.py | 23 ++--
imagefactory/builders/RHELBuilder.py | 7 +-
imagefactory/builders/__init__.py | 2 +-
imagefactory/qmfagent/BuildAdaptor.py | 52 ++++----
imagefactory/qmfagent/ImageFactoryAgent.py | 29 +++---
imgfac.py | 1 +
scripts/tests/build_push_ovisan.py | 3 +-
tests/builders/testBaseBuilder.py | 36 +++---
tests/builders/testFedoraBuilder.py | 12 +-
tests/builders/testMockBuilder.py | 10 +-
tests/builders/testRHELBuilder.py | 12 +-
tests/qmfagent/testBuildAdaptor.py | 16 ++--
tests/qmfagent/testImageFactory.py | 16 ++--
tests/qmfagent/testImageFactoryAgent.py | 42 ++++----
tests/testApplicationConfiguration.py | 16 ++--
tests/testImageWarehouse.py | 16 ++--
tests/testTemplate.py | 16 ++--
24 files changed, 355 insertions(+), 366 deletions(-)
diff --git a/imagefactory/BuildDispatcher.py b/imagefactory/BuildDispatcher.py
index bed7280..e30e15e 100644
--- a/imagefactory/BuildDispatcher.py
+++ b/imagefactory/BuildDispatcher.py
@@ -1,14 +1,14 @@
# Copyright (C) 2010-2011 Red Hat, Inc.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
@@ -24,13 +24,13 @@ from imagefactory.Template import Template
class BuildDispatcher(object):
-
+
@classmethod
def builder_for_target_with_template(cls, target, template):
log = logging.getLogger('%s.%s' % (__name__, cls.__name__))
-
+
template_object = Template(template)
-
+
builder_class = MockBuilder.MockBuilder
if (target != "mock"): # If target is mock always run mock builder
regardless of template
parsed_doc = libxml2.parseDoc(template_object.xml)
@@ -43,18 +43,17 @@ class BuildDispatcher(object):
builder_class = getattr(sys.modules[module_name], class_name)
except AttributeError, e:
log.exception("CAUGHT EXCEPTION: %s \n Could not find builder class
for %s, returning MockBuilder!", e, os_name)
-
+
return builder_class(template_object, target)
-
+
@classmethod
def builder_thread_with_method(cls, builder, method_name, arg_dict={},
autostart=True):
log = logging.getLogger('%s.%s' % (__name__, cls.__name__))
-
+
thread_name = "%s.%s()" % (builder.image_id, method_name)
# using args to pass the method we want to call on the target object.
builder_thread = Thread(target = builder, name=thread_name, args=(method_name),
kwargs=arg_dict)
if(autostart):
builder_thread.start()
-
+
return builder_thread
-
diff --git a/imagefactory/ImageWarehouse.py b/imagefactory/ImageWarehouse.py
index 844771b..0549e86 100644
--- a/imagefactory/ImageWarehouse.py
+++ b/imagefactory/ImageWarehouse.py
@@ -28,7 +28,7 @@ from imagefactory.ApplicationConfiguration import
ApplicationConfiguration
class ImageWarehouse(object):
-
+
# Properties
def url():
doc = "The url property."
@@ -40,7 +40,7 @@ class ImageWarehouse(object):
del self._url
return locals()
url = property(**url())
-
+
def image_bucket():
doc = "The image_bucket property."
def fget(self):
@@ -51,7 +51,7 @@ class ImageWarehouse(object):
del self._image_bucket
return locals()
image_bucket = property(**image_bucket())
-
+
def template_bucket():
doc = "The template_bucket property."
def fget(self):
@@ -62,7 +62,7 @@ class ImageWarehouse(object):
del self._template_bucket
return locals()
template_bucket = property(**template_bucket())
-
+
def icicle_bucket():
doc = "The icicle_bucket property."
def fget(self):
@@ -73,7 +73,7 @@ class ImageWarehouse(object):
del self._icicle_bucket
return locals()
icicle_bucket = property(**icicle_bucket())
-
+
def provider_image_bucket():
doc = "The provider_image_bucket property."
def fget(self):
@@ -84,36 +84,36 @@ class ImageWarehouse(object):
del self._provider_image_bucket
return locals()
provider_image_bucket = property(**provider_image_bucket())
-
+
# Properties end
-
+
def __repr__(self):
return "%s - %r" % (super(ImageWarehouse, self).__repr__(),
self.__dict__)
-
+
def __str__(self):
return "%s - buckets(%s, %s, %s, %s)" % (self.url, self.image_bucket,
self.template_bucket, self.icicle_bucket, self.provider_image_bucket)
-
+
def __init__(self, url=None):
self.log = logging.getLogger('%s.%s' % (__name__,
self.__class__.__name__))
-
+
self.http = httplib2.Http()
-
+
if(not url):
url = ApplicationConfiguration().configuration['warehouse']
self.log.debug("Property (url) not specified. Pulling from application
configuration: %s" % (url, ))
-
+
self.image_bucket =
ApplicationConfiguration().configuration['image_bucket']
self.template_bucket =
ApplicationConfiguration().configuration['template_bucket']
self.icicle_bucket =
ApplicationConfiguration().configuration['icicle_bucket']
self.provider_image_bucket =
ApplicationConfiguration().configuration['provider_bucket']
-
+
if (url.endswith('/')):
self.url = url[0:len(url)-1]
else:
self.url = url
-
+
self.log.debug("Created Image Warehouse instance %s" % (self, ))
-
+
def create_bucket_at_url(self, url):
try:
response_headers, response = self.http.request(url, "PUT",
headers={'content-type':'text/plain'})
@@ -126,7 +126,7 @@ class ImageWarehouse(object):
return True
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
def __url_for_id_of_type(self, object_id, object_type, create=True):
bucket = getattr(self, "_%s_bucket" % (object_type, ))
if(bucket):
@@ -135,17 +135,17 @@ class ImageWarehouse(object):
object_url = "%s/%s/%s" % (self.url, bucket, object_id)
else:
object_url ="%s/%s" % (self.url, object_id)
-
+
return object_url
def post_on_object_with_id_of_type(self, object_id, object_type, post_data):
object_url = self.__url_for_id_of_type(object_id, object_type, create=False)
try:
- response_headers, response = self.http.request(object_url, "POST",
urllib.urlencode(post_data), headers={'Content-Type':
'application/x-www-form-urlencoded'})
+ response_headers, response = self.http.request(object_url, "POST",
urllib.urlencode(post_data), headers={'Content-Type':
'application/x-www-form-urlencoded'})
return response
except Exception, e:
raise WarehouseError("Problem encountered trying to POST to image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
def object_with_id_of_type(self, object_id, object_type, metadata_keys=()):
object_url = self.__url_for_id_of_type(object_id, object_type, create=False)
try:
@@ -157,17 +157,17 @@ class ImageWarehouse(object):
return response, metadata
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
def object_for_image_id(self, image_id, object_type, metadata_keys=()):
object_url = self.__url_for_id_of_type(image_id, "image",
create=False)
try:
response_headers, object_id = self.http.request("%s/%s" %
(object_url, object_type), "GET",
headers={'content-type':'text/plain'})
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
the_object, metadata = self.object_with_id_of_type(object_id, object_type,
metadata_keys)
return object_id, the_object, metadata
-
+
def delete_object_at_url(self, object_url):
try:
response_headers, response = self.http.request(object_url,
"DELETE", headers={'content-type':'text/plain'})
@@ -179,15 +179,15 @@ class ImageWarehouse(object):
return False
except Exception, e:
raise WarehouseError("Problem encountered trying to delete object at
%s.\nPlease check that iwhd is running and reachable.\nException text: %s" %
(object_url, e))
-
+
def delete_object_with_id_of_type(self, object_id, object_type):
object_url = self.__url_for_id_of_type(object_id, object_type, create=False)
return self.delete_object_at_url(object_url)
-
+
def set_metadata_for_id_of_type(self, metadata, object_id, object_type):
object_url = self.__url_for_id_of_type(object_id, object_type, create=False)
self.set_metadata_for_object_at_url(metadata, object_url)
-
+
def set_metadata_for_object_at_url(self, metadata, object_url):
try:
self.log.debug("Setting metadata (%s) for %s" % (metadata,
object_url))
@@ -195,11 +195,11 @@ class ImageWarehouse(object):
response_header, response = self.http.request("%s/%s" %
(object_url, item), "PUT", body=str(metadata[item]),
headers={'content-type':'text/plain'})
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
def metadata_for_id_of_type(self, metadata_keys, object_id, object_type):
object_url = self.__url_for_id_of_type(object_id, object_type, create=False)
return self.metadata_for_object_at_url(metadata_keys, object_url)
-
+
def metadata_for_object_at_url(self, metadata_keys, object_url):
try:
self.log.debug("Getting metadata (%s) from %s" % (metadata_keys,
object_url))
@@ -210,12 +210,12 @@ class ImageWarehouse(object):
return metadata
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
def store_image(self, image_id, image_file_path, metadata=None):
object_url = self.__url_for_id_of_type(image_id, "image")
try:
image_file = open(image_file_path)
-
+
# Upload the image itself
image_size = os.path.getsize(image_file_path)
curl = pycurl.Curl()
@@ -229,12 +229,12 @@ class ImageWarehouse(object):
image_file.close()
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
meta_data = dict(uuid=str(image_id), object_type="image")
if(metadata):
meta_data.update(metadata)
self.set_metadata_for_object_at_url(meta_data, object_url)
-
+
def create_provider_image(self, image_id, txt=None, metadata=None):
object_url = self.__url_for_id_of_type(image_id,
object_type="provider_image")
if(not txt):
@@ -242,82 +242,81 @@ class ImageWarehouse(object):
txt = "This object has the following metadata keys: %s" %
(metadata.keys(), )
else:
txt = "This object only exists to hold metadata."
-
+
try:
response_headers, response = self.http.request(object_url, "PUT",
body=txt, headers={'content-type':'text/plain'})
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
meta_data = dict(uuid=str(image_id), object_type="provider_image")
if(metadata):
meta_data.update(metadata)
self.set_metadata_for_object_at_url(meta_data, object_url)
-
+
def store_template(self, template, template_id=None, metadata=None):
if(not template_id):
template_id = uuid.uuid4()
object_url = self.__url_for_id_of_type(template_id,
object_type="template")
-
+
try:
response_headers, response = self.http.request(object_url, "PUT",
body=template, headers={'content-type':'text/plain'})
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
meta_data = dict(uuid=str(template_id), object_type="template")
if(metadata):
meta_data.update(metadata)
self.set_metadata_for_object_at_url(meta_data, object_url)
-
- return template_id
-
+
+ return template_id
+
def store_icicle(self, icicle, icicle_id=None, metadata=None):
if(not icicle_id):
icicle_id = uuid.uuid4()
object_url = self.__url_for_id_of_type(icicle_id,
object_type="icicle")
-
+
try:
response_headers, response = self.http.request(object_url, "PUT",
body=icicle, headers={'content-type':'text/plain'})
except Exception, e:
raise WarehouseError("Problem encountered trying to reach image
warehouse. Please check that iwhd is running and reachable.\nException text: %s" %
(e, ))
-
+
meta_data = dict(uuid=str(icicle_id), object_type="icicle")
if(metadata):
meta_data.update(metadata)
self.set_metadata_for_object_at_url(meta_data, object_url)
-
- return icicle_id
-
+
+ return icicle_id
+
def icicle_with_id(self, icicle_id, metadata_keys=()):
return self.object_with_id_of_type(icicle_id, "icicle", metadata_keys)
-
+
def icicle_for_image_id(self, image_id, metadata_keys=()):
return self.object_for_image_id(image_id, "icicle", metadata_keys)
-
+
def template_with_id(self, template_id, metadata_keys=()):
return self.object_with_id_of_type(template_id, "template",
metadata_keys)
-
+
def template_for_image_id(self, image_id, metadata_keys=()):
return self.object_for_image_id(image_id, "template", metadata_keys)
-
+
def image_with_id(self, image_id, metadata_keys=()):
return self.object_with_id_of_type(image_id, "image", metadata_keys)
-
+
def remove_template_with_id(self, template_id):
return self.delete_object_with_id_of_type(template_id, "template")
-
+
def remove_icicle_with_id(self, icicle_id):
return self.delete_object_with_id_of_type(icicle_id, "icicle")
-
+
def remove_image_with_id(self, image_id):
return self.delete_object_with_id_of_type(image_id, "image")
-
+
class WarehouseError(Exception):
"""Error related to image warehouse interactions."""
def __init__(self, value):
super(WarehouseError, self).__init__()
self.value = value
-
+
def __str__(self):
return repr(self.value)
-
diff --git a/imagefactory/Template.py b/imagefactory/Template.py
index 90ef1fd..af005a1 100644
--- a/imagefactory/Template.py
+++ b/imagefactory/Template.py
@@ -28,7 +28,7 @@ from imagefactory.ImageWarehouse import ImageWarehouse
class Template(object):
uuid_pattern =
'([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})'
-
+
# Properties
def identifier():
doc = "The identifier property."
@@ -40,7 +40,7 @@ class Template(object):
del self._identifier
return locals()
identifier = property(**identifier())
-
+
def url():
doc = "The url property."
def fget(self):
@@ -51,7 +51,7 @@ class Template(object):
del self._url
return locals()
url = property(**url())
-
+
def xml():
doc = "The xml property."
def fget(self):
@@ -62,22 +62,22 @@ class Template(object):
del self._xml
return locals()
xml = property(**xml())
-
-
+
+
def __repr__(self):
if(self.xml):
return self.xml
else:
return super(Template, self).__repr__
-
+
def __init__(self, template=None, uuid=None, url=None, xml=None):
self.log = logging.getLogger('%s.%s' % (__name__,
self.__class__.__name__))
self.warehouse =
ImageWarehouse(ApplicationConfiguration().configuration["warehouse"])
-
+
self.identifier = None
self.url = None
self.xml = None
-
+
if(template):
template_string = str(template)
template_string_type = self.__template_string_type(template_string)
@@ -87,7 +87,7 @@ class Template(object):
url = template_string
elif(template_string_type == "XML"):
xml = template_string
-
+
if(uuid):
uuid_string = uuid
self.identifier, self.xml = self.__fetch_template_for_uuid(uuid_string)
@@ -108,11 +108,11 @@ class Template(object):
raise ValueError("File %s does not contain properly formatted
template xml:\n%s" % (template_string, self.__abbreviated_template(file_content)))
else:
raise ValueError("'template' must be a UUID, URL, or XML
document...")
-
+
def __template_string_type(self, template_string):
regex = re.compile(Template.uuid_pattern)
match = regex.search(template_string)
-
+
if(template_string.lower().startswith("http")):
return "URL"
elif(("<template>" in template_string.lower()) and
("</template>" in template_string.lower())):
@@ -121,9 +121,9 @@ class Template(object):
return "UUID"
elif(os.path.exists(template_string)):
return "PATH"
- else:
+ else:
raise ValueError("'template_string' must be a UUID, URL, or XML
document...\n--- TEMPLATE STRING ---\n%s\n-----------------" % (template_string, ))
-
+
def __fetch_template_for_uuid(self, uuid_string):
xml_string, metadata = self.warehouse.template_with_id(uuid_string)
if(xml_string and self.__string_is_xml_template(xml_string)):
@@ -136,28 +136,27 @@ class Template(object):
else:
self.log.debug("Unable to fetch a valid template given an image id
%s:\n%s\n" % (uuid_string, self.__abbreviated_template(xml_string)))
return None, None
-
+
def __string_is_xml_template(self, text):
return (("<template>" in text.lower()) and
("</template>" in text.lower()))
-
+
def __fetch_template_with_url(self, url):
template_id = None
regex = re.compile(Template.uuid_pattern)
match = regex.search(url)
-
+
if (match):
template_id = uuid.UUID(match.group())
-
+
response_headers, response = httplib2.Http().request(url, "GET",
headers={'content-type':'text/plain'})
if(response and self.__string_is_xml_template(response)):
return template_id, response
else:
raise RuntimeError("Recieved status %s fetching a template from %s!\n---
Response Headers:\n%s\n--- Response:\n%s" % (response_headers["status"],
url, response_headers, response))
-
+
def __abbreviated_template(self, template_string):
lines = template_string.splitlines(True)
if(len(lines) > 20):
return "%s\n...\n...\n...\n%s" % ("".join(lines[0:10]),
"".join(lines[-10:len(lines)]))
else:
return template_string
-
diff --git a/imagefactory/builders/BaseBuilder.py b/imagefactory/builders/BaseBuilder.py
index 5f9a1e0..b9546fa 100644
--- a/imagefactory/builders/BaseBuilder.py
+++ b/imagefactory/builders/BaseBuilder.py
@@ -27,11 +27,11 @@ from imagefactory.ImageWarehouse import ImageWarehouse
from imagefactory.Template import Template
class BaseBuilder(object):
- """BaseBuilder provides a starting point for builder classes
conforming to the IBuilder interface.
- Subclasses of BaseBuilder can focus on the OS/Provider specific activity for creating
and
+ """BaseBuilder provides a starting point for builder classes
conforming to the IBuilder interface.
+ Subclasses of BaseBuilder can focus on the OS/Provider specific activity for creating
and
deploying images."""
zope.interface.implements(IBuilder)
-
+
# Properties
def template():
doc = "An instance of the Template class."
@@ -43,7 +43,7 @@ class BaseBuilder(object):
del self._template
return locals()
template = property(**template())
-
+
def target():
doc = "The target cloud for which to build this image."
def fget(self):
@@ -54,7 +54,7 @@ class BaseBuilder(object):
del self._target
return locals()
target = property(**target())
-
+
def target_id():
doc = "The identifier provided by the target."
def fget(self):
@@ -65,7 +65,7 @@ class BaseBuilder(object):
del self._target_id
return locals()
target_id = property(**target_id())
-
+
def provider():
doc = "The a string name of the target region or provider."
def fget(self):
@@ -76,7 +76,7 @@ class BaseBuilder(object):
del self._provider
return locals()
provider = property(**provider())
-
+
def image_id():
doc = "The uuid of the image."
def fget(self):
@@ -87,7 +87,7 @@ class BaseBuilder(object):
del self._image_id
return locals()
image_id = property(**image_id())
-
+
def image():
doc = "The image file path."
def fget(self):
@@ -98,12 +98,12 @@ class BaseBuilder(object):
del self._image
return locals()
image = property(**image())
-
+
def status():
doc = "A string value."
def fget(self):
return self._status
-
+
def fset(self, value):
if(self.delegate):
try: #check with the delegate if we should update
@@ -125,12 +125,12 @@ class BaseBuilder(object):
self._status = value
return locals()
status = property(**status())
-
+
def percent_complete():
doc = "The percentage through an operation."
def fget(self):
return self._percent_complete
-
+
def fset(self, value):
if(self.delegate):
try: #check with the delegate if we should update
@@ -150,10 +150,10 @@ class BaseBuilder(object):
pass
else:
self._percent_complete = value
-
+
return locals()
percent_complete = property(**percent_complete())
-
+
def output_descriptor():
doc = "An XML string describing the completed image, aka: CDL or
ICICLE."
def fget(self):
@@ -164,7 +164,7 @@ class BaseBuilder(object):
del self._output_descriptor
return locals()
output_descriptor = property(**output_descriptor())
-
+
def delegate():
doc = "An object that responds to IBuilderDelegate methods."
def fget(self):
@@ -175,7 +175,7 @@ class BaseBuilder(object):
del self._delegate
return locals()
delegate = property(**delegate())
-
+
def warehouse():
doc = "A warehouse object used to store/fetch images, templates, icicle,
provider_images, etc..."
def fget(self):
@@ -186,7 +186,7 @@ class BaseBuilder(object):
del self._warehouse
return locals()
warehouse = property(**warehouse())
-
+
# Initializer
def __init__(self, template, target):
super(BaseBuilder, self).__init__()
@@ -207,31 +207,30 @@ class BaseBuilder(object):
self.output_descriptor = "<icicle></icicle>"
self.delegate = None
self.warehouse =
ImageWarehouse(ApplicationConfiguration().configuration["warehouse"])
-
+
# Make instances callable for passing to thread objects
def __call__(self, *args, **kwargs):
# the method that we want to call on self is in args... kwargs is the method
parameters, if there are any.
getattr(self, str().join(args))(**kwargs)
-
+
# Image actions
def build_image(self):
- """Build the image file. This method is implemented by subclasses
of BaseBuilder to handle
+ """Build the image file. This method is implemented by subclasses
of BaseBuilder to handle
OS specific build mechanics."""
raise NotImplementedError
-
+
def abort(self):
- """Stop building the image file. This method is implemented by
subclasses of BaseBuilder to handle
+ """Stop building the image file. This method is implemented by
subclasses of BaseBuilder to handle
OS specific build mechanics."""
raise NotImplementedError
-
+
def store_image(self, target_parameters=None):
template_id = self.warehouse.store_template(self.template.xml,
self.template.identifier)
icicle_id = self.warehouse.store_icicle(self.output_descriptor)
metadata = dict(template=template_id, target=self.target, icicle=icicle_id,
target_parameters=target_parameters)
self.warehouse.store_image(self.image_id, self.image, metadata=metadata)
-
+
def push_image(self, image_id, provider, credentials):
- """Prep the image for the provider and deploy. This method is
implemented by subclasses of the
+ """Prep the image for the provider and deploy. This method is
implemented by subclasses of the
BaseBuilder to handle OS/Provider specific mechanics."""
raise NotImplementedError
-
diff --git a/imagefactory/builders/FedoraBuilder.py
b/imagefactory/builders/FedoraBuilder.py
index 4926162..39edf76 100644
--- a/imagefactory/builders/FedoraBuilder.py
+++ b/imagefactory/builders/FedoraBuilder.py
@@ -49,7 +49,7 @@ from VMDKstream import convert_to_stream
def subprocess_check_output(*popenargs, **kwargs):
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
-
+
process = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
*popenargs, **kwargs)
stdout, stderr = process.communicate()
retcode = process.poll()
@@ -78,14 +78,14 @@ class FedoraBuilder(BaseBuilder):
# Reference vars - don't change these
# EC2 is a special case as it can be either and is set in the config file
upload_clouds = [ "rhev-m", "vmware", "condorcloud" ]
- nonul_clouds = [ "rackspace", "gogrid" ]
+ nonul_clouds = [ "rackspace", "gogrid" ]
def __init__(self, template, target):
super(FedoraBuilder, self).__init__(template, target)
self.app_config = ApplicationConfiguration().configuration
self.warehouse_url = self.app_config['warehouse']
# TODO: Should this be in base? Does image_id ever need to be an actual UUID
object?
- self.image_id = str(self.image_id)
+ self.image_id = str(self.image_id)
# May not be necessary to do both of these
self.tdlobj = oz.TDL.TDL(xmlstring=self.template.xml)
@@ -100,7 +100,7 @@ class FedoraBuilder(BaseBuilder):
if guesttype == "local":
self.guest = oz.Fedora.get_class(self.tdlobj, config, None)
else:
- self.guest = FedoraRemoteGuest(self.tdlobj, config, None, "virtio",
True, "virtio", True)
+ self.guest = FedoraRemoteGuest(self.tdlobj, config, None, "virtio",
True, "virtio", True)
self.guest.diskimage = self.app_config["imgdir"] +
"/base-image-" + self.image_id + ".dsk"
# Oz assumes unique names - TDL built for multiple backends guarantees they are
not unique
# We don't really care about the name so just force uniqueness
@@ -179,7 +179,7 @@ class FedoraBuilder(BaseBuilder):
raise
finally:
self.guest.cleanup_install()
-
+
self.log.debug("Generated disk image (%s)" % (self.guest.diskimage))
# OK great, we now have a customized KVM image
# Now we do some target specific transformation
@@ -192,12 +192,12 @@ class FedoraBuilder(BaseBuilder):
self.ec2_transform_image()
elif self.target == "vmware":
self.log.info("Transforming image for use on VMWare")
- self.vmware_transform_image()
+ self.vmware_transform_image()
if (self.app_config['warehouse']):
self.log.debug("Storing Fedora image at %s..." %
(self.app_config['warehouse'], ))
# TODO: Revisit target_parameters for different providers
-
+
if self.target in [ "condorcloud", "rhev-m" ]:
# TODO: Prune any unneeded elements
target_parameters=libvirt_xml
@@ -210,7 +210,7 @@ class FedoraBuilder(BaseBuilder):
self.status="COMPLETED"
def vmware_transform_image(self):
- # On entry the image points to our generic KVM raw image
+ # On entry the image points to our generic KVM raw image
# Convert to stream-optimized VMDK and then update the image property
target_image = self.app_config['imgdir'] + "/vmware-image-" +
self.image_id + ".vmdk"
self.log.debug("Converting raw kvm image (%s) to vmware stream-optimized
image (%s)" % (self.image, target_image))
@@ -264,24 +264,24 @@ class FedoraBuilder(BaseBuilder):
g.sync ()
g.umount_all ()
-
+
def ec2_copy_filesystem(self, output_dir):
target_image=output_dir + "/ec2-image-" + self.image_id +
".dsk"
-
+
self.log.debug("init guestfs")
g = guestfs.GuestFS ()
-
+
self.log.debug("add input image")
g.add_drive (self.image)
-
+
self.log.debug("creat target image")
f = open (target_image, "w")
# TODO: Can this be larger, smaller - should it be?
f.truncate (10000 * 1024 * 1024)
f.close ()
g.add_drive(target_image)
-
+
self.log.debug("creat tmp image")
# We need a small FS to mount target and dest on - make image file for it
# TODO: Use Marek's create mount point trick instead of a temp file
@@ -290,16 +290,16 @@ class FedoraBuilder(BaseBuilder):
f.truncate (10 * 1024 * 1024)
f.close
g.add_drive(tmp_image_file)
-
+
self.log.debug("launch guestfs")
g.launch ()
-
+
# TODO: Re-enable this?
# Do inspection here, as libguestfs prefers we do it before mounting anything
#inspection = g.inspect_os()
# This assumes, I think reasonably, only one OS on the disk image provided by Oz
#rootdev = inspection[0]
-
+
# At this point sda is original image - sdb is blank target - sdc is small
helper
self.log.info("Making filesystems for EC2 transform")
# TODO: Make different FS types depending on the type of the original root fs
@@ -316,20 +316,20 @@ class FedoraBuilder(BaseBuilder):
g.mount_ro ("/dev/VolGroup00/LogVol00", "/in")
g.mount_ro ("/dev/sda1", "/in/boot")
g.mount_options ("", "/dev/sdb", "/out/in")
-
+
self.log.info("Copying image contents to EC2 flat filesystem")
g.cp_a("/in/", "/out")
self.log.info("Done")
-
+
g.sync ()
g.umount_all ()
os.unlink(tmp_image_file)
-
+
# Save the original image file name but update our property to point to new EC2
image
# TODO: Delete the original image?
self.original_image = self.image
self.image = target_image
-
+
def ec2_modify_filesystem(self):
# Modifications
# Many of these are more or less directly ported from BoxGrinder
@@ -338,39 +338,39 @@ class FedoraBuilder(BaseBuilder):
# TODO: This would be safer and more robust if done within the running modified
# guest - in this would require tighter Oz integration
-
+
g = guestfs.GuestFS ()
-
+
g.add_drive(self.image)
g.launch ()
-
+
# Do inspection here, as libguestfs prefers we do it before mounting anything
inspection = g.inspect_os()
# This should always be /dev/vda or /dev/sda but we do it anyway to be safe
- osroot = inspection[0]
-
+ osroot = inspection[0]
+
# eg "fedora"
distro = g.inspect_get_distro(osroot)
arch = g.inspect_get_arch(osroot)
major_version = g.inspect_get_major_version(osroot)
minor_version = g.inspect_get_minor_version(osroot)
-
+
self.log.debug("distro: %s - arch: %s - major: %s - minor %s" %
(distro, arch, major_version, minor_version))
-
+
g.mount_options ("", osroot, "/")
-
+
self.log.info("Modifying flat FS contents to be EC2 compatible")
-
+
self.log.info("Disabling SELINUX")
tmpl = '# Factory Disabled SELINUX -
sorry\nSELINUX=permissive\nSELINUXTYPE=targeted\n'
g.write("/etc/sysconfig/selinux", tmpl)
-
+
# Make a /data directory for 64 bit hosts
# Ephemeral devs come pre-formatted from AWS - weird
if arch == "x86_64":
self.log.info("Making data directory")
g.mkdir("/data")
-
+
# BG - Upload one of two templated fstabs
# Input - root device name
# PREFIX is xv unless we are dealing with RHEL5, which is interesting - must mean
we hack
@@ -381,28 +381,28 @@ class FedoraBuilder(BaseBuilder):
# TODO: Match OS default behavior and/or what is found in the existing image
prefix="xv"
fstype="ext3"
-
+
self.log.info("Modifying and uploading fstab")
# Make arch conditional
if arch == "x86_64":
tmpl=self.fstab_64bit
else:
tmpl=self.fstab_32bit
-
+
tmpl = string.replace(tmpl, "#DISK_DEVICE_PREFIX#", prefix)
tmpl = string.replace(tmpl, "#FILESYSTEM_TYPE#", fstype)
g.write("/etc/fstab", tmpl)
-
+
# BG - Enable networking
# Upload a known good ifcfg-eth0 and then chkconfig on networking
self.log.info("Enabling networking and uploading ifcfg-eth0")
g.sh("/sbin/chkconfig network on")
g.write("/etc/sysconfig/network-scripts/ifcfg-eth0", self.ifcfg_eth0)
-
+
# Disable first boot - this slows things down otherwise
if g.is_file("/etc/init.d/firstboot"):
g.sh("/sbin/chkconfig firstboot off")
-
+
# BG - Upload rc.local extra content
# Again, this uses a static copy - this bit is where the ssh key is downloaded
# TODO: Is this where we inject puppet?
@@ -411,11 +411,11 @@ class FedoraBuilder(BaseBuilder):
self.log.info("Updating rc.local for key injection")
g.write("/tmp/rc.local", self.rc_local)
g.sh("cat /tmp/rc.local >> /etc/rc.local")
-
+
# Install menu list
# Derive the kernel version from the last element of ls /lib/modules and some
# other magic - look at linux_helper for details
-
+
# Look at /lib/modules and assume that the last kernel listed is the version we
use
self.log.info("Modifying and updating menu.lst")
kernel_versions = g.ls("/lib/modules")
@@ -438,23 +438,23 @@ class FedoraBuilder(BaseBuilder):
self.log.debug("Using kernel version: %s" % (kernel_version))
-
+
# We could deduce this from version but it's easy to inspect
bootramfs = int(g.sh("ls -1 /boot | grep initramfs | wc -l"))
ramfs_prefix = "initramfs" if bootramfs > 0 else "initrd"
-
+
name="Image Factory EC2 boot - kernel: " + kernel_version
if (distro == "rhel") and (major_version == 5):
g.sh("/sbin/mkinitrd -f -v --preload xenblk --preload xennet
/boot/initrd-%s.img %s" % (kernel_version))
-
+
tmpl = self.menu_lst
tmpl = string.replace(tmpl, "#KERNEL_VERSION#", kernel_version)
tmpl = string.replace(tmpl, "#KERNEL_IMAGE_NAME#", ramfs_prefix)
tmpl = string.replace(tmpl, "#TITLE#", name)
-
- g.write("/boot/grub/menu.lst", tmpl)
-
+
+ g.write("/boot/grub/menu.lst", tmpl)
+
# F14 bug fix
# This fixes issues with Fedora 14 on EC2:
https://bugzilla.redhat.com/show_bug.cgi?id=651861#c39
if (distro == "fedora") and (major_version == 14):
@@ -462,13 +462,13 @@ class FedoraBuilder(BaseBuilder):
g.sh("echo \"hwcap 1 nosegneg\" >
/etc/ld.so.conf.d/libc6-xen.conf")
g.sh("/sbin/ldconfig")
self.log.info("Done with EC2 filesystem modifications")
-
+
g.sync ()
g.umount_all ()
-
+
# TODO: Based on architecture associate one of two XML blocks that contain the
correct
# regional AKIs for pvgrub
-
+
def push_image(self, image_id, provider, credentials):
try:
if self.target in self.upload_clouds or (self.target == "ec2" and
self.app_config["ec2_build_style"] == "upload"):
@@ -704,7 +704,7 @@ chmod 600 /root/.ssh/authorized_keys
# Now launch it
reservation =
conn.run_instances(ami_id,instance_type=instance_type,user_data=user_data, security_groups
= [ factory_security_group_name ])
-
+
if len(reservation.instances) != 1:
self.status="FAILED"
raise ImageFactoryException("run_instances did not result in the
expected single instance - stopping")
@@ -818,7 +818,7 @@ chmod 600 /root/.ssh/authorized_keys
else:
raise
# TODO: End of copy
-
+
# TODO: We cannot timeout on any of the three commands below - can we fix
that?
manifest = "/mnt/bundles/%s.manifest.xml" % (uuid)
command = 'euca-upload-bundle -b %s -m %s --ec2cert /tmp/cert-ec2.pem -a
"%s" -s "%s" -U %s' % (bucket, manifest, self.ec2_access_key,
self.ec2_secret_key, upload_url)
@@ -857,7 +857,7 @@ chmod 600 /root/.ssh/authorized_keys
input_image = self.app_config["imgdir"] + "/base-image-" +
image_id + ".dsk"
# Grab from Warehouse if it isn't here
self.retrieve_image(image_id, input_image)
-
+
storage = "/home/cloud/images"
if not os.path.isdir(storage):
raise ImageFactoryException("Storage dir (%s) for condorcloud is not
present" % (storage))
@@ -865,7 +865,7 @@ chmod 600 /root/.ssh/authorized_keys
staging = storage + "/staging"
if not os.path.isdir(staging):
raise ImageFactoryException("Staging dir (%s) for condorcloud is not
present" % (staging))
-
+
image_base = "/condorimage-" + str(self.image_id) + ".img"
staging_image = staging + image_base
@@ -882,7 +882,7 @@ chmod 600 /root/.ssh/authorized_keys
image_metadata =
self.warehouse.metadata_for_id_of_type(("target_parameters",), image_id,
"image")
self.log.debug("Got metadata output of: %s", repr(image_metadata))
libvirt_xml = image_metadata["target_parameters"]
-
+
f = open(image_xml_file, 'w')
f.write(libvirt_xml)
f.close()
@@ -990,10 +990,10 @@ chmod 600 /root/.ssh/authorized_keys
raise
self.status="COMPLETED"
- def ec2_decode_credentials(self, credentials):
+ def ec2_decode_credentials(self, credentials):
doc = libxml2.parseDoc(credentials)
ctxt = doc.xpathNewContext()
-
+
self.ec2_user_id =
ctxt.xpathEval("//provider_credentials/ec2_credentials/account_number")[0].content
self.ec2_access_key =
ctxt.xpathEval("//provider_credentials/ec2_credentials/access_key")[0].content
self.ec2_secret_key =
ctxt.xpathEval("//provider_credentials/ec2_credentials/secret_access_key")[0].content
@@ -1017,14 +1017,14 @@ chmod 600 /root/.ssh/authorized_keys
ec2_cert = ec2_cert_node[0].content
doc.freeDoc()
- ctxt.xpathFreeContext()
-
+ ctxt.xpathFreeContext()
+
# Shove certs into named temporary files
self.ec2_cert_file_object = NamedTemporaryFile()
self.ec2_cert_file_object.write(ec2_cert)
self.ec2_cert_file_object.flush()
self.ec2_cert_file=self.ec2_cert_file_object.name
-
+
self.ec2_key_file_object = NamedTemporaryFile()
self.ec2_key_file_object.write(ec2_key)
self.ec2_key_file_object.flush()
@@ -1047,20 +1047,20 @@ chmod 600 /root/.ssh/authorized_keys
fp.close()
else:
self.log.debug("Image file %s already present - skipping warehouse
download" % (local_image_file))
-
+
def ec2_push_image_upload(self, image_id, provider, credentials):
- self.ec2_decode_credentials(credentials)
+ self.ec2_decode_credentials(credentials)
# if the image is already here, great, otherwise grab it from the warehouse
input_image_path=self.app_config['imgdir'] + "/"
input_image_name="ec2-image-" + image_id + ".dsk"
input_image=input_image_path + input_image_name
-
+
self.retrieve_image(image_id, input_image)
bundle_destination=self.app_config['imgdir']
-
+
# TODO: Cross check against template XML and warn if they do not match
g = guestfs.GuestFS ()
g.add_drive(input_image)
@@ -1074,9 +1074,9 @@ chmod 600 /root/.ssh/authorized_keys
self.log.debug("Warning - unable to inspect EC2 image file - assuming
x86_64 arch")
arch = "x86_64"
g.umount_all()
-
+
self.percent_complete=10
-
+
# TODO: Ideally we should use boto "Location" references when possible
- 1.9 contains only DEFAULT and EU
# The rest are hard coded strings for now.
ec2_region_details=\
@@ -1085,10 +1085,10 @@ chmod 600 /root/.ssh/authorized_keys
'ec2-ap-southeast-1': { 'boto_loc': 'ap-southeast-1',
'host':'ap-southeast-1', 'i386': 'aki-13d5aa41',
'x86_64': 'aki-11d5aa43' },
'ec2-ap-northeast-1': { 'boto_loc': 'ap-northeast-1',
'host':'ap-northeast-1', 'i386': 'aki-d209a2d3',
'x86_64': 'aki-d409a2d5' },
'ec2-eu-west-1': { 'boto_loc': Location.EU,
'host':'eu-west-1', 'i386': 'aki-4deec439',
'x86_64': 'aki-4feec43b' } }
-
+
region=provider
region_conf=ec2_region_details[region]
- aki = region_conf[arch]
+ aki = region_conf[arch]
boto_loc = region_conf['boto_loc']
if region != "ec2-us-east-1":
upload_url = "http://s3-%s.amazonaws.com/" %
(region_conf['host'])
@@ -1097,9 +1097,9 @@ chmod 600 /root/.ssh/authorized_keys
upload_url = "http://s3.amazonaws.com/"
register_url = "http://ec2.%s.amazonaws.com/" %
(region_conf['host'])
-
+
bucket= "imagefactory-" + region + "-" + self.ec2_user_id
-
+
# Euca does not support specifying region for bucket
# (Region URL is not sufficient)
# See:
https://bugs.launchpad.net/euca2ools/+bug/704658
@@ -1116,33 +1116,33 @@ chmod 600 /root/.ssh/authorized_keys
pass
else:
raise
-
+
# TODO: Make configurable?
ec2_service_cert = "/etc/pki/imagefactory/cert-ec2.pem"
-
+
bundle_command = [ "euca-bundle-image", "-i", input_image,
"--kernel", aki, "-d", bundle_destination, "-a",
self.ec2_access_key, "-s", self.ec2_secret_key ]
bundle_command.extend( [ "-c", self.ec2_cert_file ] )
bundle_command.extend( [ "-k", self.ec2_key_file ] )
bundle_command.extend( [ "-u", self.ec2_user_id ] )
bundle_command.extend( [ "-r", arch ] )
bundle_command.extend( [ "--ec2cert", ec2_service_cert ] )
-
+
self.log.debug("Executing bundle command: %s " % (bundle_command))
-
+
bundle_output = subprocess_check_output(bundle_command)
-
+
self.log.debug("Bundle command complete")
self.log.debug("Bundle command output: %s " % (str(bundle_output)))
self.percent_complete=40
-
+
manifest = bundle_destination + "/" + input_image_name +
".manifest.xml"
-
+
upload_command = [ "euca-upload-bundle", "-b", bucket,
"-m", manifest, "--ec2cert", ec2_service_cert, "-a",
self.ec2_access_key, "-s", self.ec2_secret_key, "-U" , upload_url ]
self.log.debug("Executing upload command: %s " % (upload_command))
upload_output = subprocess_check_output(upload_command)
self.log.debug("Upload command output: %s " % (str(upload_output)))
self.percent_complete=90
-
+
s3_path = bucket + "/" + input_image_name + ".manifest.xml"
register_env = { 'EC2_URL':register_url }
@@ -1153,32 +1153,32 @@ chmod 600 /root/.ssh/authorized_keys
m = re.match(".*(ami-[a-fA-F0-9]+)", register_output[0])
ami_id = m.group(1)
self.log.debug("Extracted AMI ID: %s " % (ami_id))
-
+
# TODO: This should be in a finally statement that rethrows exceptions
self.ec2_cert_file_object.close()
self.ec2_key_file_object.close()
-
+
# Use new warehouse wrapper to do everything
# TODO: Generate and store ICICLE
self.status = "PUSHING"
metadata = dict(image=image_id, provider=provider, icicle="none",
target_identifier=ami_id)
self.warehouse.create_provider_image(self.image_id, metadata=metadata)
-
+
#self.output_descriptor="unknown"
#metadata = dict(uuid=self.image_id, type="provider_image",
template=self.template, target=self.target, icicle=self.output_descriptor, image=image_id,
provider=provider, target_identifier=ami_id)
self.log.debug("FedoraBuilder instance %s pushed image with uuid %s to
provider_image UUID (%s) and set metadata: %s" % (id(self), str(image_id),
str(self.image_id), str(metadata)))
self.percent_complete=100
-
+
def abort(self):
pass
-
+
# This file content is tightly bound up with our mod code above
# I've inserted it as class variables for convenience
rc_local="""# We have seen timing issues with curl commands - try
several times
for t in 1 2 3 4 5 6 7 8 9 10; do
echo "Try number $t" >> /tmp/ec2-keypull.stderr
curl -o /tmp/my-key
http://169.254.169.254/2009-04-04/meta-data/public-keys/0/openssh-key 2>>
/tmp/ec2-keypull.stderr
- [ -f /tmp/my-key ] && break
+ [ -f /tmp/my-key ] && break
sleep 10
done
@@ -1222,7 +1222,7 @@ fi
# This conditionally runs Audrey if it exists
[ -f /usr/bin/audrey ] && /usr/bin/audrey
"""
-
+
ifcfg_eth0="""DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
@@ -1231,7 +1231,7 @@ USERCTL=yes
PEERDNS=yes
IPV6INIT=no
"""
-
+
menu_lst="""default=0
timeout=0
title #TITLE#
@@ -1239,7 +1239,7 @@ title #TITLE#
kernel /boot/vmlinuz-#KERNEL_VERSION# ro root=LABEL=/ rd_NO_PLYMOUTH
initrd /boot/#KERNEL_IMAGE_NAME#-#KERNEL_VERSION#.img
"""
-
+
fstab_32bit="""LABEL=/ / #FILESYSTEM_TYPE# defaults
1 1
/dev/#DISK_DEVICE_PREFIX#da2 /mnt ext3 defaults 1 2
/dev/#DISK_DEVICE_PREFIX#da3 swap swap defaults 0 0
@@ -1248,7 +1248,7 @@ none /dev/shm tmpfs defaults 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0
"""
-
+
fstab_64bit="""LABEL=/ / #FILESYSTEM_TYPE# defaults
1 1
/dev/#DISK_DEVICE_PREFIX#db /mnt ext3 defaults 0 0
/dev/#DISK_DEVICE_PREFIX#dc /data ext3 defaults 0 0
@@ -1257,7 +1257,7 @@ none /dev/shm tmpfs defaults 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0
"""
-
+
# Dont attempt to be clever with ephemeral devices - leave it to users
fstab_generic="""LABEL=/ / #FILESYSTEM_TYPE# defaults
1 1
none /dev/pts devpts gid=5,mode=620 0 0
diff --git a/imagefactory/builders/IBuilder.py b/imagefactory/builders/IBuilder.py
index f4f4bbd..39c92d5 100644
--- a/imagefactory/builders/IBuilder.py
+++ b/imagefactory/builders/IBuilder.py
@@ -23,7 +23,7 @@ from zope.interface import Invalid
def conforms_to_interface_invariant(obj):
- """Invariant method testing for mandatory aspects of the interface.
+ """Invariant method testing for mandatory aspects of the interface.
Returns 'Invalid' exception if the implementing object does not
conform."""
try:
getattr(obj, "template")
@@ -44,7 +44,7 @@ def conforms_to_interface_invariant(obj):
class IBuilder(Interface):
- """The Builder interface provides guidance on attributes and methods
+ """The Builder interface provides guidance on attributes and methods
that expected by Image Factory for objects that serve to build OS
images."""
# set the invariant checks
zope.interface.invariant(conforms_to_interface_invariant)
@@ -62,10 +62,9 @@ class IBuilder(Interface):
# methods
def build_image():
"""Tell the builder to start building the
image."""
-
+
def abort():
"""Tell the builder to stop building the image."""
-
+
def push_image(image_id, provider, credentials):
"""Deploy an image to the cloud provider."""
-
diff --git a/imagefactory/builders/IBuilderDelegate.py
b/imagefactory/builders/IBuilderDelegate.py
index 5ac096c..de91708 100644
--- a/imagefactory/builders/IBuilderDelegate.py
+++ b/imagefactory/builders/IBuilderDelegate.py
@@ -25,25 +25,24 @@ class IBuilderDelegate(Interface):
Subclasses of the BaseBuilder class will get this for free. Classes
that conform to the IBuilderDelegate interface can selectively
implement methods from this interface."""
-
+
def builder_will_update_status(self, builder, original_status, new_status):
"""The builder will update from original_status to
new_status."""
-
+
def builder_did_update_status(self, builder, original_status, new_status):
"""The builder updated the status from original_status to
new_status."""
-
+
def builder_should_update_status(self, builder, original_status, new_status):
"""Returns whether the builder should update the status from
original_status to new_status."""
-
+
def builder_will_update_percentage(self, builder, original_percentage,
new_percentage):
"""The builder will update from original_percentage to
new_percentage."""
-
+
def builder_did_update_percentage(self, builder, original_percentage,
new_percentage):
"""The builder updated from original_percentage to
new_percentage."""
-
+
def builder_should_update_percentage(self, builder, original_percentage,
new_percentage):
"""Returns whether the builder should update from
original_percentage to new_percentage."""
-
+
def builder_did_fail(self, builder, failure_type, failure_info):
"""Notification that there was a failure of specified type, with
further information describing what happened."""
-
diff --git a/imagefactory/builders/MockBuilder.py b/imagefactory/builders/MockBuilder.py
index 1e52537..18719f4 100644
--- a/imagefactory/builders/MockBuilder.py
+++ b/imagefactory/builders/MockBuilder.py
@@ -32,13 +32,13 @@ from imagefactory.ApplicationConfiguration import
ApplicationConfiguration
class MockBuilder(BaseBuilder):
"""docstring for MockBuilder"""
zope.interface.implements(IBuilder)
-
+
# Initializer
def __init__(self,
template="<template><name>Mock</name></template>",
target='mock'):
super(MockBuilder, self).__init__(template, target)
self.log = logging.getLogger('%s.%s' % (__name__,
self.__class__.__name__))
self.app_config = ApplicationConfiguration().configuration
-
+
# Image actions
def build_image(self):
if(self.template.xml == "<template>FAIL</template>"):
@@ -52,11 +52,11 @@ class MockBuilder(BaseBuilder):
self.status = "INITIALIZING"
self.log.debug("Initializing mock image...")
self.percent_complete = 0
-
+
directory = os.path.dirname(self.image)
if (not os.path.exists(directory)):
os.makedirs(directory)
-
+
with open(self.image, 'w') as image_file:
self.status = "PENDING"
self.log.debug("Building mock image...")
@@ -73,7 +73,7 @@ class MockBuilder(BaseBuilder):
image_file.write(":created_by: %s\n" %
(sys.argv[0].rpartition('/')[2], ))
image_file.write(":created_on: %s\n" % (time.strftime("%a,
%d %b %Y %H:%M:%S +0000", time.gmtime()), ))
image_file.close()
-
+
self.percent_complete = 50
self.percent_complete = 75
self.percent_complete = 95
@@ -82,9 +82,9 @@ class MockBuilder(BaseBuilder):
self.percent_complete = 100
self.status = "COMPLETED"
self.log.debug("Completed mock image build...")
-
+
self.store_image()
-
+
def push_image(self, image_id, provider, credentials):
self.status = "INITIALIZING"
try:
@@ -108,10 +108,10 @@ class MockBuilder(BaseBuilder):
except Exception, e:
failing_thread = FailureThread(target=self,
kwargs=dict(message="%s" % (e, )))
failing_thread.start()
-
+
def abort(self):
self.log.debug("Method abort() called on MockBuilder instance %s" %
(id(self), ))
-
+
class FailureThread(Thread):
"""docstring for FailureThread"""
@@ -119,10 +119,7 @@ class FailureThread(Thread):
super(FailureThread, self).__init__(group=None, target=None, name=None, args=(),
kwargs={})
self.target = target
self.message = kwargs["message"]
-
+
def run(self):
time.sleep(1)
self.target.delegate.builder_did_fail(self, "Mock", self.message)
-
-
-
\ No newline at end of file
diff --git a/imagefactory/builders/RHELBuilder.py b/imagefactory/builders/RHELBuilder.py
index 9e1f08e..3f8d1be 100644
--- a/imagefactory/builders/RHELBuilder.py
+++ b/imagefactory/builders/RHELBuilder.py
@@ -24,15 +24,14 @@ from BaseBuilder import BaseBuilder
class RHELBuilder(BaseBuilder):
"""docstring for RHELBuilder"""
zope.interface.implements(IBuilder)
-
+
# Initializer
def __init__(self, template=None, target=None):
super(RHELBuilder, self).__init__(template, target)
-
+
# Image actions
def build_image(self):
pass
-
+
def abort(self):
pass
-
diff --git a/imagefactory/builders/__init__.py b/imagefactory/builders/__init__.py
index fa51456..0b13628 100644
--- a/imagefactory/builders/__init__.py
+++ b/imagefactory/builders/__init__.py
@@ -16,4 +16,4 @@
# MA 02110-1301, USA. A copy of the GNU General Public License is
# also available at
http://www.gnu.org/copyleft/gpl.html.
-__all__ = ["IBuilder", "IBuilderDelegate", "BaseBuilder",
"MockBuilder", "RHELBuilder", "FedoraBuilder"]
\ No newline at end of file
+__all__ = ["IBuilder", "IBuilderDelegate", "BaseBuilder",
"MockBuilder", "RHELBuilder", "FedoraBuilder"]
diff --git a/imagefactory/qmfagent/BuildAdaptor.py
b/imagefactory/qmfagent/BuildAdaptor.py
index 93c1b7b..ab064d0 100644
--- a/imagefactory/qmfagent/BuildAdaptor.py
+++ b/imagefactory/qmfagent/BuildAdaptor.py
@@ -1,14 +1,14 @@
# Copyright (C) 2010-2011 Red Hat, Inc.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
@@ -31,7 +31,7 @@ class BuildAdaptor(object):
qmf_schema.addProperty(SchemaProperty("percent_complete", SCHEMA_DATA_INT,
desc="the estimated percentage through an operation"))
qmf_schema.addProperty(SchemaProperty("image_id", SCHEMA_DATA_STRING,
desc="string representation of the assigned uuid"))
qmf_schema.addMethod(SchemaMethod("abort", desc = "If possible, abort
running build."))
-
+
#QMF schema for status change event
qmf_event_schema_status = Schema(SCHEMA_TYPE_EVENT,
"com.redhat.imagefactory", "BuildAdaptorStatusEvent")
qmf_event_schema_status.addProperty(SchemaProperty("addr", SCHEMA_DATA_MAP,
desc="the address of the object raising this event"))
@@ -49,7 +49,7 @@ class BuildAdaptor(object):
qmf_event_schema_build_failed.addProperty(SchemaProperty("event",
SCHEMA_DATA_STRING, desc="string describing the type of event, in this case
'FAILURE'"))
qmf_event_schema_build_failed.addProperty(SchemaProperty("type",
SCHEMA_DATA_STRING, desc="short string description of the failure"))
qmf_event_schema_build_failed.addProperty(SchemaProperty("info",
SCHEMA_DATA_STRING, desc="longer string description of the failure"))
-
+
@classmethod
def object_states(cls):
"""Returns a dictionary representing the finite state machine for
instances of this class."""
@@ -60,8 +60,8 @@ class BuildAdaptor(object):
"FINISHING":({"COMPLETED":("_auto_")},
{"FAILED":("_auto_")}),
"COMPLETED":()
}
-
-
+
+
### Properties
def template():
doc = "The template property."
@@ -73,7 +73,7 @@ class BuildAdaptor(object):
del self._template
return locals()
template = property(**template())
-
+
def target():
doc = "The target property."
def fget(self):
@@ -84,7 +84,7 @@ class BuildAdaptor(object):
del self._target
return locals()
target = property(**target())
-
+
def status():
doc = "The status property."
def fget(self):
@@ -96,7 +96,7 @@ class BuildAdaptor(object):
del self._status
return locals()
status = property(**status())
-
+
def percent_complete():
doc = "The percent_complete property."
def fget(self):
@@ -108,7 +108,7 @@ class BuildAdaptor(object):
del self._percent_complete
return locals()
percent_complete = property(**percent_complete())
-
+
def image_id():
doc = "The image property."
def fget(self):
@@ -120,7 +120,7 @@ class BuildAdaptor(object):
del self._image_id
return locals()
image = property(**image_id())
-
+
def qmf_object():
doc = "The qmf_object property."
def fget(self):
@@ -131,36 +131,36 @@ class BuildAdaptor(object):
del self._qmf_object
return locals()
qmf_object = property(**qmf_object())
-
+
def __init__(self, template, target, agent=None):
super(BuildAdaptor, self).__init__()
-
+
self.log = logging.getLogger('%s.%s' % (__name__,
self.__class__.__name__))
self.qmf_object = Data(BuildAdaptor.qmf_schema)
- self.agent = agent
-
+ self.agent = agent
+
self.template = template
self.target = target
self.status = "New"
self.percent_complete = 0
self.image = "None"
self.builder = None
-
+
self.builder =
BuildDispatcher.builder_for_target_with_template(template=template, target=target)
# Register as a delegate to the builder
self.builder.delegate = self
self.image = str(self.builder.image_id)
-
+
def build_image(self):
BuildDispatcher.builder_thread_with_method(builder=self.builder,
method_name="build_image")
-
+
def push_image(self, image_id, provider, credentials):
kwargs = dict(image_id=image_id, provider=provider, credentials=credentials)
BuildDispatcher.builder_thread_with_method(builder=self.builder,
method_name="push_image", arg_dict=kwargs)
-
+
def abort(self):
self.builder.abort()
-
+
# Builder delegate methods
def builder_did_update_status(self, builder, old_status, new_status):
self.status = new_status
@@ -171,11 +171,11 @@ class BuildAdaptor(object):
event.new_status = str(new_status)
event.old_status = str(old_status)
self.agent.session.raiseEvent(data=event, severity=SEV_NOTICE)
-
+
if(new_status == "COMPLETED"):
self.agent.deregister(self.qmf_object)
-
-
+
+
def builder_did_update_percentage(self, builder, original_percentage,
new_percentage):
self.percent_complete = new_percentage
self.log.debug("Raising event with agent handler (%s), changed percent
complete from %s to %s" % (self.agent, original_percentage, new_percentage))
@@ -184,7 +184,7 @@ class BuildAdaptor(object):
event.event = "PERCENTAGE"
event.percent_complete = new_percentage
self.agent.session.raiseEvent(data=event, severity=SEV_NOTICE)
-
+
def builder_did_fail(self, builder, failure_type, failure_info):
self.log.debug("Raising event with agent handler (%s), BUILD FAILED: %s -
%s" % (self.agent, failure_type, failure_info))
event = Data(BuildAdaptor.qmf_event_schema_build_failed)
@@ -193,7 +193,7 @@ class BuildAdaptor(object):
event.type = failure_type
event.info = failure_info
self.agent.session.raiseEvent(data=event, severity=SEV_ERROR)
-
+
# if __name__ == '__main__':
# unittest.main()
diff --git a/imagefactory/qmfagent/ImageFactoryAgent.py
b/imagefactory/qmfagent/ImageFactoryAgent.py
index 2dbb0c2..62f5452 100644
--- a/imagefactory/qmfagent/ImageFactoryAgent.py
+++ b/imagefactory/qmfagent/ImageFactoryAgent.py
@@ -1,14 +1,14 @@
# Copyright (C) 2010-2011 Red Hat, Inc.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
@@ -34,7 +34,7 @@ class ImageFactoryAgent(AgentHandler):
del self._qmf_object
return locals()
qmf_object = property(**qmf_object())
-
+
def managedObjects():
doc = "The managedObjects property."
def fget(self):
@@ -45,8 +45,8 @@ class ImageFactoryAgent(AgentHandler):
# del self._managedObjects
return locals()
managedObjects = property(**managedObjects())
-
-
+
+
def __init__(self, url):
self.log = logging.getLogger('%s.%s' % (__name__,
self.__class__.__name__))
self._managedObjects = {}
@@ -73,25 +73,25 @@ class ImageFactoryAgent(AgentHandler):
self.image_factory.agent = self
self.image_factory_addr = self.session.addData(self.image_factory.qmf_object,
"image_factory")
self.log.info("image_factory has qmf/qpid address: %s",
self.image_factory_addr)
-
+
## AgentHandler override
def method(self, handle, methodName, args, subtypes, addr, userId):
"""
Handle incoming method calls.
"""
self.log.debug("Method called: name = %s \n args = %s \n handle = %s \n addr
= %s \n subtypes = %s \n userId = %s", methodName, args, handle, addr, subtypes,
userId)
-
+
try:
-
+
if (addr == self.image_factory_addr):
target_obj = self.image_factory
elif (repr(addr) in self.managedObjects):
target_obj = self.managedObjects[repr(addr)]
else:
raise RuntimeError("%s does not match an object managed by
ImageFactoryAgent! Unable to respond to %s." % (repr(addr), methodName))
-
+
result = getattr(target_obj, methodName)(**args)
-
+
if ((addr == self.image_factory_addr) and (methodName in ("image",
"provider_image"))):
build_adaptor_instance_name = "build_adaptor:%s:%s" %
(methodName, result.builder.image_id)
qmf_object_addr = self.session.addData(result.qmf_object,
build_adaptor_instance_name, persistent=True)
@@ -113,7 +113,7 @@ class ImageFactoryAgent(AgentHandler):
except Exception, e:
self.log.exception(str(e))
self.session.raiseException(handle, str(e))
-
+
def shutdown(self):
"""
Clean up the session and connection. Cancel the running thread.
@@ -126,7 +126,7 @@ class ImageFactoryAgent(AgentHandler):
except Exception, e:
self.log.exception(e)
return False
-
+
def deregister(self, managed_object):
"""
Remove an item from the agents collection of managed objects.
@@ -138,9 +138,8 @@ class ImageFactoryAgent(AgentHandler):
managed_object_key = repr(managed_object)
elif(managed_object.__class__ == str):
managed_object_key = managed_object
-
+
try:
del self.managedObjects[managed_object_key]
except KeyError:
self.log.error("Trying to remove object (%s) from managedObjects that
does not exist..." % (managed_object_key, ))
-
diff --git a/imgfac.py b/imgfac.py
index 64fa701..53cd2f1 100755
--- a/imgfac.py
+++ b/imgfac.py
@@ -179,6 +179,7 @@ class Application(object):
self.builder_thread =
BuildDispatcher.builder_thread_with_method(self.builder, 'push_image', kwargs)
print("Image instance created with id: %s" %
(self.builder.image_id, ))
+
if __name__ == "__main__":
application = Application()
sys.exit(application.main())
diff --git a/scripts/tests/build_push_ovisan.py b/scripts/tests/build_push_ovisan.py
index 0caddbf..486afba 100755
--- a/scripts/tests/build_push_ovisan.py
+++ b/scripts/tests/build_push_ovisan.py
@@ -28,7 +28,7 @@ class iCurl:
self.contents = ''
def body_callback(self, buf):
- self.contents = self.contents + buf
+ self.contents = self.contents + buf
if len(sys.argv) != 5:
@@ -116,4 +116,3 @@ else:
session.close()
connection.close()
-
diff --git a/tests/builders/testBaseBuilder.py b/tests/builders/testBaseBuilder.py
index 1fc141a..a75e265 100644
--- a/tests/builders/testBaseBuilder.py
+++ b/tests/builders/testBaseBuilder.py
@@ -31,100 +31,100 @@ class TestBaseBuilder(unittest.TestCase):
self.builder =
BaseBuilder(template="<template></template>",
target="mock")
self.delegate = BuilderDelegate()
self.new_builder_status = "NEW_STATUS"
-
+
def tearDown(self):
del self.builder
del self.delegate
del self.new_builder_status
-
+
def testImplementsIBuilder(self):
self.assert_(IBuilder.implementedBy(BaseBuilder), 'BaseBuilder does not
implement the ImageBuilder interface.')
try:
IBuilder.validateInvariants(self.builder)
except Invalid, e:
self.fail(e)
-
+
def testIsCallable(self):
self.assert_(callable(self.builder))
-
+
def testImageIdSet(self):
self.assert_(self.builder.image_id, 'Initilizer failed to set
\'image_id\'...')
-
+
def testDelegateAssignment(self):
self.builder.delegate = self.delegate
self.assertIs(self.builder.delegate, self.delegate)
-
+
def testShouldUpdateStatus(self):
self.builder.status = "UPDATE_ME"
self.builder.delegate = self.delegate
self.builder.status = self.new_builder_status
self.assertEqual(self.new_builder_status, self.builder.status)
self.builder.delegate = None
-
+
def testShouldNotUpdateStatus(self):
self.builder.status = "NO_UPDATE"
self.builder.delegate = self.delegate
self.builder.status = self.new_builder_status
self.assertEqual("NO_UPDATE", self.builder.status)
self.builder.delegate = None
-
+
def testModifyStatusUpdate(self):
self.builder.status = "INSERT_CHANGE"
self.builder.delegate = self.delegate
self.builder.status = self.new_builder_status
self.assertEqual("MODIFIED_STATUS_UPDATE", self.builder.status)
self.builder.delegate = None
-
+
def testModifyPercentageUpdate(self):
self.builder.percent_complete = None
self.builder.delegate = self.delegate
self.builder.percent_complete = 50
self.assertEqual(self.builder.percent_complete, 0)
self.builder.delegate = None
-
+
def testShouldUpdatePercentage(self):
self.builder.percent_complete = 50
self.builder.delegate = self.delegate
self.builder.percent_complete = 95
self.assertEqual(95, self.builder.percent_complete)
self.builder.delegate = None
-
+
def testShouldNotUpdatePercentage(self):
self.builder.percent_complete = 100
self.builder.delegate = self.delegate
self.builder.percent_complete = 52
self.assertEqual(100, self.builder.percent_complete)
self.builder.delegate = None
-
+
class BuilderDelegate(object):
zope.interface.implements(IBuilderDelegate)
-
+
def builder_should_update_status(self, builder, original_status, new_status):
if(original_status == "NO_UPDATE"):
return False
else:
return True
-
+
def builder_will_update_status(self, builder, original_status, new_status):
if(original_status == "INSERT_CHANGE"):
return "MODIFIED_STATUS_UPDATE"
else:
return new_status
-
+
def builder_will_update_percentage(self, builder, original_percentage,
new_percentage):
if(original_percentage >= 0):
return new_percentage
else:
return 0
-
+
def builder_should_update_percentage(self, builder, original_percentage,
new_percentage):
if(original_percentage == 100):
return False
else:
return True
-
+
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/tests/builders/testFedoraBuilder.py b/tests/builders/testFedoraBuilder.py
index bf476d8..853f761 100644
--- a/tests/builders/testFedoraBuilder.py
+++ b/tests/builders/testFedoraBuilder.py
@@ -20,17 +20,17 @@
# import logging
# from imagefactory.builders.IBuilder import IBuilder
# from imagefactory.builders.FedoraBuilder import FedoraBuilder
-#
-#
+#
+#
# class TestFedoraBuilder(unittest.TestCase):
# def setUp(self):
# pass
-#
+#
# def tearDown(self):
# pass
-#
+#
# def testImplementsIBuilder(self):
# self.assert_(IBuilder.implementedBy(FedoraBuilder), 'FedoraBuilder does not
implement the ImageBuilder interface.')
-#
+#
# if __name__ == '__main__':
-# unittest.main()
\ No newline at end of file
+# unittest.main()
diff --git a/tests/builders/testMockBuilder.py b/tests/builders/testMockBuilder.py
index 6f8cb5d..27aaa4e 100644
--- a/tests/builders/testMockBuilder.py
+++ b/tests/builders/testMockBuilder.py
@@ -31,24 +31,24 @@ class TestMockBuilder(unittest.TestCase):
self.template = Template("<template></template>")
self.target = "mock"
self.builder = MockBuilder(self.template, self.target)
-
+
def tearDown(self):
del self.builder
del self.template
del self.target
-
+
def testImplementsIBuilder(self):
self.assert_(IBuilder.implementedBy(MockBuilder), 'MockBuilder does not
implement the ImageBuilder interface...')
-
+
def testInit(self):
self.assertIn(self.builder.template, (self.template, self.builder.image_id))
self.assertEqual(self.builder.target, self.target)
-
+
def testBuildImage(self):
self.builder.build_image()
self.assertEqual(self.builder.status, "COMPLETED")
self.assert_(os.path.exists(self.builder.image))
-
+
if __name__ == '__main__':
diff --git a/tests/builders/testRHELBuilder.py b/tests/builders/testRHELBuilder.py
index c951402..5903296 100644
--- a/tests/builders/testRHELBuilder.py
+++ b/tests/builders/testRHELBuilder.py
@@ -20,17 +20,17 @@
# import logging
# from imagefactory.builders.IBuilder import IBuilder
# from imagefactory.builders.RHELBuilder import RHELBuilder
-#
-#
+#
+#
# class TestRHELBuilder(unittest.TestCase):
# def setUp(self):
# pass
-#
+#
# def tearDown(self):
# pass
-#
+#
# def testImplementsIBuilder(self):
# self.assert_(IBuilder.implementedBy(RHELBuilder), 'RHELBuilder does not
implement the ImageBuilder interface.')
-#
+#
# if __name__ == '__main__':
-# unittest.main()
\ No newline at end of file
+# unittest.main()
diff --git a/tests/qmfagent/testBuildAdaptor.py b/tests/qmfagent/testBuildAdaptor.py
index 77c7c9b..026923e 100644
--- a/tests/qmfagent/testBuildAdaptor.py
+++ b/tests/qmfagent/testBuildAdaptor.py
@@ -1,14 +1,14 @@
# Copyright (C) 2010-2011 Red Hat, Inc.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
@@ -38,10 +38,10 @@ class TestBuildAdaptor(unittest.TestCase):
<description>Fedora 14</description>
</template>
"""
-
+
def tearDown(self):
del self.tdl_string
-
+
def testQMFSchemaDefinition(self):
expected_schema_properties = ("status", "percent_complete",
"image_id")
expected_schema_methods = dict(abort=(), instance_states=("class_name",
"states"))
@@ -52,13 +52,13 @@ class TestBuildAdaptor(unittest.TestCase):
arguments = expected_schema_methods[schema_method.getName()]
for schema_property in schema_method.getArguments():
self.assertIn(schema_property.getName(), arguments)
-
+
def testInstantiateMockBuilder(self):
build_adaptor = BuildAdaptor(template=self.tdl_string, target="mock")
self.assertIsInstance(build_adaptor.builder, MockBuilder.MockBuilder)
self.assertEqual(build_adaptor.template, self.tdl_string)
self.assertEqual(build_adaptor.target, "mock")
-
+
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/tests/qmfagent/testImageFactory.py b/tests/qmfagent/testImageFactory.py
index c0ee274..38c7efc 100644
--- a/tests/qmfagent/testImageFactory.py
+++ b/tests/qmfagent/testImageFactory.py
@@ -1,14 +1,14 @@
# Copyright (C) 2010-2011 Red Hat, Inc.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
@@ -25,20 +25,20 @@ class TestImageFactory(unittest.TestCase):
def setUp(self):
logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)s
%(name)s pid(%(process)d) Message: %(message)s',
filename='/tmp/imagefactory-unittests.log')
pass
-
+
def tearDown(self):
pass
-
+
def testQMFSchemaDefinition(self):
- expected_schema_methods = dict(image=("template", "target",
"build_adaptor"),
- provider_image=("image_id",
"provider", "credentials", "build_adaptor"),
+ expected_schema_methods = dict(image=("template", "target",
"build_adaptor"),
+ provider_image=("image_id",
"provider", "credentials", "build_adaptor"),
instance_states=("class_name",
"states"))
for schema_method in ImageFactory.qmf_schema.getMethods():
self.assertIn(schema_method.getName(), expected_schema_methods)
arguments = expected_schema_methods[schema_method.getName()]
for schema_property in schema_method.getArguments():
self.assertIn(schema_property.getName(), arguments)
-
+
def testSingleton(self):
image_factory_one = ImageFactory()
image_factory_two = ImageFactory()
diff --git a/tests/qmfagent/testImageFactoryAgent.py
b/tests/qmfagent/testImageFactoryAgent.py
index bed7e81..aa4f37d 100644
--- a/tests/qmfagent/testImageFactoryAgent.py
+++ b/tests/qmfagent/testImageFactoryAgent.py
@@ -1,14 +1,14 @@
# Copyright (C) 2010-2011 Red Hat, Inc.
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
@@ -37,7 +37,7 @@ class TestImageFactoryAgent(unittest.TestCase):
self.console = MockConsole(self.console_session,
self.if_agent.image_factory_addr)
self.console.start()
time.sleep(5) # Give the agent some time to show up.
-
+
def tearDown(self):
del self.expected_state_transitions
self.console.cancel()
@@ -48,12 +48,12 @@ class TestImageFactoryAgent(unittest.TestCase):
del self.connection
self.if_agent.shutdown()
del self.if_agent
-
+
def testImageFactoryAgent(self):
"""Test agent registration, method calls, and
events"""
# test for the correct version of the qmf2 bindings
self.assertTrue(hasattr(AgentSession(self.connection), "raiseEvent"))
-
+
# test the build failure qmf event raised by BuildAdaptor
self.assertEqual(len(self.console.test_failure_events), 1)
self.assertEqual(len(self.console.real_failure_events), 0, "Unexpected
failure events raised!\n%s" % (self.console.real_failure_events, ))
@@ -61,19 +61,19 @@ class TestImageFactoryAgent(unittest.TestCase):
# test that exceptions are passed properly by the agent handler
self.assertIsInstance(self.console.image_exception, Exception)
self.assertEqual(str(self.console.image_exception), "Wrong number of
arguments: expected 2, got 0")
-
+
# test that the agent registered and consoles can see it.
try:
self.assertIsNotNone(self.console.agent)
except AttributeError:
self.fail("No imagefactory agent found...")
-
+
# test that image returns what we expect
try:
self.assertIsNotNone(self.console.build_adaptor_addr_success)
except AttributeError:
self.fail("image did not return a DataAddr for build_adaptor...")
-
+
# test that status changes in build adaptor create QMF events the consoles see.
agent_name = self.console.agent.getName()
self.assertEqual(len(self.expected_state_transitions),
len(self.console.build_status_events))
@@ -85,13 +85,13 @@ class TestImageFactoryAgent(unittest.TestCase):
self.assertEqual(self.console.build_adaptor_addr_success,
properties["addr"])
self.assertEqual(self.expected_state_transitions[index][0],properties["old_status"])
self.assertEqual(self.expected_state_transitions[index][1],properties["new_status"])
-
+
# test that provider_image returns what we expect
try:
self.assertIsNotNone(self.console.build_adaptor_addr_push)
except AttributeError:
self.fail("provider_image did not return a DataAddr for
build_adaptor...")
-
+
# test that status changes in build adaptor create QMF events the consoles see.
self.assertGreater(len(self.console.push_status_events), 0)
# self.assertEqual(len(self.expected_state_transitions),
len(self.console.push_status_events))
@@ -103,11 +103,11 @@ class TestImageFactoryAgent(unittest.TestCase):
# self.assertEqual(self.console.build_adaptor_addr_push,
properties["addr"])
#
self.assertEqual(self.expected_state_transitions[index][0],properties["old_status"])
#
self.assertEqual(self.expected_state_transitions[index][1],properties["new_status"])
-
+
# test instance_states method
self.assertIsNotNone(self.console.image_factory_states)
self.assertIsNotNone(self.console.build_adaptor_states)
-
+
class MockConsole(ConsoleHandler):
def __init__(self, consoleSession, agent_addr):
@@ -121,27 +121,27 @@ class MockConsole(ConsoleHandler):
self.test_failure_events = []
self.real_failure_events = []
self.event_count = 0
-
+
def agentAdded(self, agent):
if(str(self.agent_addr).startswith(agent.getName())):
self.agent = agent
self.factory = agent.query("{class:ImageFactory,
package:'com.redhat.imagefactory'}")[0]
self.build_adaptor_addr_success =
self.factory.image("<template></template>",
"mock")["build_adaptor"]
self.build_adaptor_addr_fail =
self.factory.image("<template>FAIL</template>",
"mock")["build_adaptor"]
-
+
self.image_factory_states =
self.factory.instance_states("ImageFactory")
self.build_adaptor_states =
self.factory.instance_states("BuildAdaptor")
-
+
try:
self.image_exception = self.factory.image()
except Exception, e:
self.image_exception = e
-
+
def agentDeleted(self, agent, reason):
self.agent = None
self.reason_for_missing_agent = reason
print("Uh... the agent was delete because: %s" % (reason, ))
-
+
def eventRaised(self, agent, data, timestamp, severity):
if(data.getProperties()["event"] == "STATUS"):
if(data.getProperties()["addr"] ==
self.build_adaptor_addr_success):
@@ -157,9 +157,9 @@ class MockConsole(ConsoleHandler):
self.test_failure_events.append(dict(agent=agent,
data=data.getProperties(), timestamp=timestamp, severity=severity))
else:
self.real_failure_events.append(dict(agent=agent,
data=data.getProperties(), timestamp=timestamp, severity=severity))
-
+
self.event_count = self.event_count + 1
-
+
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/tests/testApplicationConfiguration.py
b/tests/testApplicationConfiguration.py
index b07a19b..190ed51 100644
--- a/tests/testApplicationConfiguration.py
+++ b/tests/testApplicationConfiguration.py
@@ -28,9 +28,9 @@ from imagefactory.ApplicationConfiguration import
ApplicationConfiguration
class TestApplicationConfiguration(unittest.TestCase):
def setUp(self):
logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)s
%(name)s pid(%(process)d) Message: %(message)s',
filename='/tmp/imagefactory-unittests.log')
-
+
self.defaults = dict(verbose=False, debug=False, foreground=False,
config="/etc/imagefactory.conf", imgdir="/tmp", qmf=False,
qpidd="localhost", warehouse=None, template=None)
-
+
config_file_path = self.defaults["config"]
if (os.path.isfile(config_file_path)):
try:
@@ -39,18 +39,18 @@ class TestApplicationConfiguration(unittest.TestCase):
config_file.close()
except IOError, e:
pass
-
-
+
+
def tearDown(self):
del self.defaults
-
+
def testSingleton(self):
self.assertIs(ApplicationConfiguration(), ApplicationConfiguration())
-
+
# def testConfigurationDictionaryDefaults(self):
# self.assertIsNotNone(ApplicationConfiguration().configuration)
# self.assertDictContainsSubset(self.defaults,
ApplicationConfiguration().configuration)
- #
+ #
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/tests/testImageWarehouse.py b/tests/testImageWarehouse.py
index 69c94ee..5f7724d 100644
--- a/tests/testImageWarehouse.py
+++ b/tests/testImageWarehouse.py
@@ -30,11 +30,11 @@ class testImageWarehouse(unittest.TestCase):
logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)s
%(name)s pid(%(process)d) Message: %(message)s',
filename='/tmp/imagefactory-unittests.log')
self.warehouse =
ImageWarehouse(ApplicationConfiguration().configuration["warehouse"])
self.metadata = dict(key1="value1", key2="value2",
key3="value3")
-
+
def tearDown(self):
del self.warehouse
del self.metadata
-
+
def testImageWarehouseMethods(self):
"""Tests CRUD operations on images, templates, icicles, and
metadata on those objects..."""
# IMAGE
@@ -51,7 +51,7 @@ class testImageWarehouse(unittest.TestCase):
# now make the assertions
self.assertEqual(file_content, image)
self.assertEqual(self.metadata, metadata)
-
+
# TEMPLATE
template_content = "<template>This is a test template. There is not
much to see here.</template>"
# store the template and let an id get assigned
@@ -71,7 +71,7 @@ class testImageWarehouse(unittest.TestCase):
template_id3, fetched_template_content3, template_metadata3 =
self.warehouse.template_for_image_id(image_id)
self.assertEqual(str(template_id), template_id3)
self.assertEqual(template_content, fetched_template_content3)
-
+
# ICICLE
icicle_content = "<icicle>This is a test icicle. There is not much to
see here.</icicle>"
# store the icicle and let an id get assigned
@@ -91,19 +91,19 @@ class testImageWarehouse(unittest.TestCase):
icicle_id3, fetched_icicle_content3, icicle_metadata3 =
self.warehouse.icicle_for_image_id(image_id)
self.assertEqual(str(icicle_id), icicle_id3)
self.assertEqual(icicle_content, fetched_icicle_content3)
-
+
self.assertTrue(self.warehouse.remove_image_with_id(image_id))
self.assertTrue(self.warehouse.remove_template_with_id(template_id))
self.assertTrue(self.warehouse.remove_template_with_id(template_id2))
self.assertTrue(self.warehouse.remove_icicle_with_id(icicle_id))
self.assertTrue(self.warehouse.remove_icicle_with_id(icicle_id2))
-
+
def testBucketCreation(self):
#
self.assert_(self.warehouse.create_bucket_at_url("%s/unittests-create_bucket/%s"
% (self.warehouse.url, uuid.uuid4())))
self.warehouse.create_bucket_at_url("%s/unittests-create_bucket" %
(self.warehouse.url, ))
self.assert_(self.warehouse.create_bucket_at_url("%s/unittests-create_bucket/%s"
% (self.warehouse.url, time.asctime().replace(' ', '-'))))
-
+
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/tests/testTemplate.py b/tests/testTemplate.py
index bd64986..ffe8e9e 100644
--- a/tests/testTemplate.py
+++ b/tests/testTemplate.py
@@ -31,18 +31,18 @@ class testTemplate(unittest.TestCase):
logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)s
%(name)s pid(%(process)d) Message: %(message)s',
filename='/tmp/imagefactory-unittests.log')
self.warehouse =
ImageWarehouse(ApplicationConfiguration().configuration["warehouse"])
self.template_xml = "<template>This is a test template. There is not
much to it.</template>"
-
+
def tearDown(self):
del self.warehouse
del self.template_xml
-
+
def testTemplateFromUUID(self):
template_id = self.warehouse.store_template(self.template_xml)
template = Template(template_id)
self.assertEqual(template_id, template.identifier)
self.assertEqual(self.template_xml, template.xml)
self.assertIsNone(template.url)
-
+
def testTemplateFramImageID(self):
template_id = self.warehouse.store_template(self.template_xml)
template = Template(template_id)
@@ -55,13 +55,13 @@ class testTemplate(unittest.TestCase):
self.assertEqual(template_id, image_template.identifier)
self.assertEqual(self.template_xml, image_template.xml)
self.assertIsNone(template.url)
-
+
def testTemplateFromXML(self):
template = Template(self.template_xml)
self.assertEqual(self.template_xml, template.xml)
self.assertIsNone(template.identifier)
self.assertIsNone(template.url)
-
+
def testTemplateFromURL(self):
template_id = self.warehouse.store_template(self.template_xml)
template_url = "%s/%s/%s" % (self.warehouse.url,
self.warehouse.template_bucket, template_id)
@@ -69,14 +69,14 @@ class testTemplate(unittest.TestCase):
self.assertEqual(template_url, template.url)
self.assertEqual(template_id, template.identifier)
self.assertEqual(self.template_xml, template.xml)
-
+
def testTemplateStringRepresentation(self):
template = Template(self.template_xml)
self.assertEqual(self.template_xml, repr(template))
self.assertEqual(self.template_xml, str(template))
self.assertEqual(self.template_xml, "%r" % (template, ))
self.assertEqual(self.template_xml, "%s" % (template, ))
-
+
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
--
1.7.4.4