frontend realms
by Jan Provazník
Hi,
patch 1 - added deletion of frontend realms into migration
patches 2-6 same as before
patch 7 - adds realms support to condormatic
13 years, 1 month
[PATCH conductor 1/2] Link log dir
by Jan Provazník
From: Jan Provaznik <jprovazn(a)redhat.com>
Log dir is linked to /var/log/aeolus-conductor in pre-install.
---
aeolus-conductor.spec.in | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/aeolus-conductor.spec.in b/aeolus-conductor.spec.in
index 45bbe9f..cb0cec8 100644
--- a/aeolus-conductor.spec.in
+++ b/aeolus-conductor.spec.in
@@ -108,7 +108,7 @@ make
%{__cp} -R src/* %{buildroot}/%{app_root}
# we need to make sure there are no leftover logfiles getting pulled in
-rm -f %{buildroot}/%{app_root}/log/*
+%{__rm} -rf %{buildroot}/%{app_root}/log
# Remove this directory as the make install below will install the correct files to this dir.
%{__rm} -rf %{buildroot}%{app_root}/classad_plugin
@@ -175,6 +175,9 @@ touch %{buildroot}%{_localstatedir}/log/%{name}/image_builder_service.log
#rake spec
%pre daemons
+[ -d %{app_root}/log ] && %{__rm} -rf %{app_root}/log
+%{__ln_s} %{_localstatedir}/log/%{name} %{app_root}/log
+
getent group aeolus >/dev/null || /usr/sbin/groupadd -g 451 -r aeolus 2>/dev/null || :
getent passwd aeolus >/dev/null || \
/usr/sbin/useradd -u 451 -g aeolus -c "aeolus" \
--
1.7.4
13 years, 1 month
[PATCH] Fix bug setting ProviderImage provider_id
by Matt Wagner
From: Matt Wagner <mawagner(a)redhat.com>
Fixes a bug where ProviderImages were always saved with provider_id => 1,
even when no Provider with that ID existed. (The 'provider' variable here
is a Provider, not its ID.)
---
src/app/models/image.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/app/models/image.rb b/src/app/models/image.rb
index 7d71089..d4b3f0b 100644
--- a/src/app/models/image.rb
+++ b/src/app/models/image.rb
@@ -97,7 +97,7 @@ class Image < ActiveRecord::Base
)
ProviderImage.create!(
:image_id => img.id,
- :provider_id => provider
+ :provider => provider
)
end
return img
--
1.7.4
13 years, 1 month
[PATCH imagefactory] Whitespace cleanup.
by Chris Lalancette
This mostly just removes unneeded whitespace at the end
of lines. It also updates the copyright headers on all of
the files that I touched.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
imagefactory/ApplicationConfiguration.py | 17 +++----
imagefactory/builders/BaseBuilder.py | 68 +++++++++++++--------------
imagefactory/builders/FedoraBuilder.py | 13 +++---
imagefactory/builders/IBuilder.py | 9 ++--
imagefactory/builders/IBuilderDelegate.py | 15 +++---
imagefactory/builders/MockBuilder.py | 25 +++++-----
imagefactory/builders/RHELBuilder.py | 9 ++--
imagefactory/qmfagent/BuildAdaptor.py | 50 ++++++++++----------
imagefactory/qmfagent/ImageFactory.py | 17 +++----
imagefactory/qmfagent/ImageFactoryAgent.py | 29 ++++++------
imgfac.py | 46 +++++++++---------
tests/builders/testBaseBuilder.py | 38 ++++++++--------
tests/builders/testMockBuilder.py | 12 +++---
tests/qmfagent/testBuildAdaptor.py | 18 ++++----
tests/qmfagent/testImageFactory.py | 18 ++++----
tests/qmfagent/testImageFactoryAgent.py | 26 +++++-----
tests/testApplicationConfiguration.py | 12 +++---
17 files changed, 206 insertions(+), 216 deletions(-)
diff --git a/imagefactory/ApplicationConfiguration.py b/imagefactory/ApplicationConfiguration.py
index 9a54398..5125b56 100644
--- a/imagefactory/ApplicationConfiguration.py
+++ b/imagefactory/ApplicationConfiguration.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# encoding: utf-8
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -25,7 +25,7 @@ import json
class ApplicationConfiguration(object):
instance = None
-
+
def configuration():
doc = "The configuration property."
def fget(self):
@@ -36,7 +36,7 @@ class ApplicationConfiguration(object):
del self._configuration
return locals()
configuration = property(**configuration())
-
+
def arguments():
doc = "The arguments property."
def fget(self):
@@ -47,18 +47,18 @@ class ApplicationConfiguration(object):
del self._arguments
return locals()
arguments = property(**arguments())
-
-
+
+
def __new__(cls, *p, **k):
if cls.instance is None:
cls.instance = object.__new__(cls, *p, **k)
return cls.instance
-
+
def __init__(self):
super(ApplicationConfiguration, self).__init__()
self.configuration = {}
self.arguments = self.parse_arguments()
-
+
if (self.arguments):
config_file_path = self.arguments.config
if (os.path.isfile(config_file_path)):
@@ -70,7 +70,7 @@ class ApplicationConfiguration(object):
argdict = self.arguments.__dict__
for key in argdict.keys():
self.configuration[key] = argdict[key]
-
+
def parse_arguments(self):
argparser = argparse.ArgumentParser(description='System image creation tool...', prog='imgfac')
argparser.add_argument('--version', action='version', version='%(prog)s 0.1', help='Version info')
@@ -92,4 +92,3 @@ class ApplicationConfiguration(object):
# return argparser.parse_args(['--debug'])
else:
return argparser.parse_args([])
-
diff --git a/imagefactory/builders/BaseBuilder.py b/imagefactory/builders/BaseBuilder.py
index 1aba768..5c4d9a7 100644
--- a/imagefactory/builders/BaseBuilder.py
+++ b/imagefactory/builders/BaseBuilder.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -30,7 +30,7 @@ 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 deploying images."""
zope.interface.implements(IBuilder)
-
+
# Properties
def template():
doc = "The template property."
@@ -42,7 +42,7 @@ class BaseBuilder(object):
del self._template
return locals()
template = property(**template())
-
+
def target():
doc = "The target property."
def fget(self):
@@ -53,7 +53,7 @@ class BaseBuilder(object):
del self._target
return locals()
target = property(**target())
-
+
def target_id():
doc = "The target_id property."
def fget(self):
@@ -64,7 +64,7 @@ class BaseBuilder(object):
del self._target_id
return locals()
target_id = property(**target_id())
-
+
def provider():
doc = "The provider property."
def fget(self):
@@ -75,7 +75,7 @@ class BaseBuilder(object):
del self._provider
return locals()
provider = property(**provider())
-
+
def image_id():
doc = "The image_id property."
def fget(self):
@@ -86,7 +86,7 @@ class BaseBuilder(object):
del self._image_id
return locals()
image_id = property(**image_id())
-
+
def image():
doc = "The image property."
def fget(self):
@@ -97,12 +97,12 @@ class BaseBuilder(object):
del self._image
return locals()
image = property(**image())
-
+
def status():
doc = "The status property."
def fget(self):
return self._status
-
+
def fset(self, value):
if(self.delegate):
try: #check with the delegate if we should update
@@ -124,12 +124,12 @@ class BaseBuilder(object):
self._status = value
return locals()
status = property(**status())
-
+
def percent_complete():
doc = "The percent_complete property."
def fget(self):
return self._percent_complete
-
+
def fset(self, value):
if(self.delegate):
try: #check with the delegate if we should update
@@ -149,10 +149,10 @@ class BaseBuilder(object):
pass
else:
self._percent_complete = value
-
+
return locals()
percent_complete = property(**percent_complete())
-
+
def output_descriptor():
doc = "The output_descriptor property."
def fget(self):
@@ -163,7 +163,7 @@ class BaseBuilder(object):
del self._output_descriptor
return locals()
output_descriptor = property(**output_descriptor())
-
+
def delegate():
doc = "The delegate property."
def fget(self):
@@ -174,8 +174,8 @@ class BaseBuilder(object):
del self._delegate
return locals()
delegate = property(**delegate())
-
-
+
+
# Initializer
def __init__(self, template=None, target=None):
super(BaseBuilder, self).__init__()
@@ -190,39 +190,39 @@ class BaseBuilder(object):
self._percent_complete = 0
self.output_descriptor = "<icicle></icicle>"
self.delegate = None
-
+
# 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 OS specific build mechanics."""
raise NotImplementedError
-
+
def abort(self):
"""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, location, target_parameters=None):
"""Store the image in an instance of Image Warehouse specified by 'location'. Any provider specific
parameters needed for later deploying images are passed as an XML block in 'target_parameters'."""
-
+
http = httplib2.Http()
http_headers = {'content-type':'text/plain'}
-
+
# since there is no way to know if the bucket exists or not, do the put on the base URL first since it seems to be non-destructive
try:
http.request(location, "PUT", headers=http_headers)
-
+
if (not location.endswith('/')):
location = "%s/" % (location, )
-
+
base_url = "%s%s" % (location, self.image_id)
self.log.debug("File (%s) to be stored at %s" % (self.image, base_url))
image_file = open(self.image)
-
+
# Upload the image itself
image_size = os.path.getsize(self.image)
curl = pycurl.Curl()
@@ -234,28 +234,28 @@ class BaseBuilder(object):
curl.perform()
curl.close()
image_file.close()
-
+
metadata = dict(uuid=self.image_id, type="image", template=self.template, target=self.target, target_parameters=target_parameters, icicle=self.output_descriptor)
self.__set_storage_metadata(base_url, metadata)
except Exception, e:
self.log.exception("Image could not be stored... Check status of image warehouse! \nCaught exception while trying to store image(%s):\n%s" % (self.image_id, e))
-
-
+
+
def __set_storage_metadata(self, url, metadata):
http = httplib2.Http()
for item in metadata:
http.request("%s/%s" % (url, item), "PUT", body=str(metadata[item]), headers={'content-type':'text/plain'})
-
+
def push_image(self, image_id, provider, credentials):
"""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
-
+
def __fetch_template(self, template_string):
if((not template_string) or (("<template>" in template_string.lower()) and ("</template>" in template_string.lower()))):
return template_string
-
+
template_url = None
-
+
try:
template_id = uuid.UUID(template_string)
template_url = "%s/%s/template" % (ApplicationConfiguration().configuration['warehouse'], template_id)
@@ -268,9 +268,7 @@ class BaseBuilder(object):
else:
self.log.warning("Template (%s) is not XML, URL, or UUID! Returning 'None'..." % (template_string, ))
return None
-
+
http = httplib2.Http()
headers, template = http.request(template_url, "GET")
return template
-
-
diff --git a/imagefactory/builders/FedoraBuilder.py b/imagefactory/builders/FedoraBuilder.py
index 692cbda..047e0c3 100644
--- a/imagefactory/builders/FedoraBuilder.py
+++ b/imagefactory/builders/FedoraBuilder.py
@@ -68,7 +68,7 @@ class FedoraBuilder(BaseBuilder):
#self.config.set('paths', 'data_dir', self.app_config["output_dir"])
self.guest = oz.Fedora.get_class(oz.TDL.TDL(xmlstring=template), self.config, None)
# TODO: Should this be global?
- self.image_id = str(self.image_id)
+ self.image_id = str(self.image_id)
# May not be necessary to do both of these
self.guest.diskimage = self.app_config["output_dir"] + "/base-image-" + self.image_id + ".dsk"
@@ -176,7 +176,7 @@ class FedoraBuilder(BaseBuilder):
self.log.debug("launch guestfs")
g.launch ()
-
+
# 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
@@ -229,7 +229,7 @@ class FedoraBuilder(BaseBuilder):
# 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)
@@ -251,7 +251,7 @@ class FedoraBuilder(BaseBuilder):
# recreate initrd using scheme described below
# g.sh("yum -y remove kernel")
# g.sh("yum -y install kernel-xen")
- # recreate INITRD
+ # recreate INITRD
# BG - create_devices
# TODO: Why?
# TODO: MAKEDEV is no longer even a standard part of F14 - force it in ks.cfg?
@@ -389,7 +389,7 @@ class FedoraBuilder(BaseBuilder):
ec2_secret_key = ctxt.xpathEval("//provider_credentials/ec2_credentials/secret_access_key")[0].content
doc.freeDoc()
- ctxt.xpathFreeContext()
+ ctxt.xpathFreeContext()
# Shove certs into named temporary files
ec2_cert_file_object = NamedTemporaryFile()
@@ -520,7 +520,7 @@ class FedoraBuilder(BaseBuilder):
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="""curl http://169.254.169.254/2009-04-04/meta-data/public-keys/0/openssh-key 2>/dev/null >/tmp/my-key
@@ -595,4 +595,3 @@ none /dev/shm tmpfs defaults 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0
"""
-
diff --git a/imagefactory/builders/IBuilder.py b/imagefactory/builders/IBuilder.py
index b9d409e..4eabc3f 100644
--- a/imagefactory/builders/IBuilder.py
+++ b/imagefactory/builders/IBuilder.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -63,13 +63,12 @@ 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 store_image(location, target_parameters):
"""Upload the completed image to an image warehouse."""
-
+
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 7cdd927..b2e0123 100644
--- a/imagefactory/builders/IBuilderDelegate.py
+++ b/imagefactory/builders/IBuilderDelegate.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -25,22 +25,21 @@ 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."""
-
diff --git a/imagefactory/builders/MockBuilder.py b/imagefactory/builders/MockBuilder.py
index 88fc8b3..60f9081 100644
--- a/imagefactory/builders/MockBuilder.py
+++ b/imagefactory/builders/MockBuilder.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -31,14 +31,14 @@ 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
self.warehouse_url = self.app_config['warehouse']
-
+
# Image actions
def build_image(self):
self.log.debug("build_image() called on MockBuilder...")
@@ -47,11 +47,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 = "BUILDING"
self.log.debug("Building mock image...")
@@ -68,7 +68,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
@@ -77,22 +77,22 @@ class MockBuilder(BaseBuilder):
self.percent_complete = 100
self.status = "COMPLETED"
self.log.debug("Completed mock image build...")
-
+
if(self.warehouse_url):
self.log.debug("Storing mock image at %s%s..." % (self.warehouse_url, self.image_id))
self.store_image(self.warehouse_url)
else:
self.log.debug("No storage location specified, skipping this step...")
-
+
def push_image(self, image_id, provider, credentials):
image_path = "%s/deltacloud-%s/%s/images/%s.yml" % (self.app_config['output'], os.getlogin(), provider, self.image_id)
original_image_url = "%s/%s" % (self.warehouse_url, image_id)
this_image_url = "%s/%s" % (self.warehouse_url, self.image_id)
http_headers = {'content-type':'text/plain'}
http = httplib2.Http()
-
+
headers_response_image, image = http.request(original_image_url, "GET")
-
+
self.log.debug("Storing mock image for %s at path: %s" % (provider, image_path))
directory = os.path.dirname(image_path)
if (not os.path.exists(directory)):
@@ -100,12 +100,11 @@ class MockBuilder(BaseBuilder):
with open(image_path, 'w') as image_file:
image_file.write(image)
image_file.close()
-
+
http.request(this_image_url, "PUT", body=image, headers=http_headers)
metadata = dict(uuid=self.image_id, type="provider_image", template=self.template, target=self.target, icicle=self.output_descriptor, image=original_image_url, provider=provider, target_identifier=this_image_url)
self.__set_storage_metadata(this_image_url, metadata)
self.log.debug("MockBuilder instance %s pushed image with uuid %s to warehouse location (%s) and set metadata: %s" % (id(self), image_id, this_image_url, metadata))
-
+
def abort(self):
self.log.debug("Method abort() called on MockBuilder instance %s" % (id(self), ))
-
diff --git a/imagefactory/builders/RHELBuilder.py b/imagefactory/builders/RHELBuilder.py
index 96d9159..3f8d1be 100644
--- a/imagefactory/builders/RHELBuilder.py
+++ b/imagefactory/builders/RHELBuilder.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -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/qmfagent/BuildAdaptor.py b/imagefactory/qmfagent/BuildAdaptor.py
index d611b06..32d5b18 100644
--- a/imagefactory/qmfagent/BuildAdaptor.py
+++ b/imagefactory/qmfagent/BuildAdaptor.py
@@ -1,14 +1,14 @@
-# Copyright (C) 2010 Red Hat, Inc.
-#
+# 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,
@@ -36,7 +36,7 @@ class BuildAdaptor(object):
# _states_method = SchemaMethod("build_states", desc = "Returns a representation of the build state transitions.")
# _states_method.addArgument(SchemaProperty("states", SCHEMA_DATA_MAP, direction=DIR_IN_OUT))
# qmf_schema.addMethod(_states_method)
-
+
#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))
@@ -48,7 +48,7 @@ class BuildAdaptor(object):
qmf_event_schema_percentage.addProperty(SchemaProperty("addr", SCHEMA_DATA_MAP))
qmf_event_schema_percentage.addProperty(SchemaProperty("event", SCHEMA_DATA_STRING))
qmf_event_schema_percentage.addProperty(SchemaProperty("percent_complete", SCHEMA_DATA_INT))
-
+
### Properties
def template():
doc = "The template property."
@@ -60,7 +60,7 @@ class BuildAdaptor(object):
del self._template
return locals()
template = property(**template())
-
+
def target():
doc = "The target property."
def fget(self):
@@ -71,7 +71,7 @@ class BuildAdaptor(object):
del self._target
return locals()
target = property(**target())
-
+
def status():
doc = "The status property."
def fget(self):
@@ -83,7 +83,7 @@ class BuildAdaptor(object):
del self._status
return locals()
status = property(**status())
-
+
def percent_complete():
doc = "The percent_complete property."
def fget(self):
@@ -95,7 +95,7 @@ class BuildAdaptor(object):
del self._percent_complete
return locals()
percent_complete = property(**percent_complete())
-
+
def image():
doc = "The image property."
def fget(self):
@@ -107,7 +107,7 @@ class BuildAdaptor(object):
del self._image
return locals()
image = property(**image())
-
+
def qmf_object():
doc = "The qmf_object property."
def fget(self):
@@ -118,22 +118,22 @@ class BuildAdaptor(object):
del self._qmf_object
return locals()
qmf_object = property(**qmf_object())
-
+
def __init__(self, template, target):
super(BuildAdaptor, self).__init__()
-
+
self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__))
self.qmf_object = Data(BuildAdaptor.qmf_schema)
# FIXME: sloranz - I should be able to get the agent from the qmf_object this is a workaround...
- self.agent = None
-
+ self.agent = None
+
self.template = template
self.target = target
self.status = "None"
self.percent_complete = 0
self.image = "None"
self.builder = None
-
+
builder_class = imagefactory.builders.MockBuilder.MockBuilder
if (self.target != "mock"): # If target is mock always run mock builder regardless of template
parsed_doc = libxml2.parseDoc(template)
@@ -145,28 +145,28 @@ class BuildAdaptor(object):
builder_class = getattr(builder_module, class_name)
except AttributeError, e:
self.log.exception("CAUGHT EXCEPTION: %s \n Could not find builder class for %s, returning MockBuilder!", e, os_name)
-
+
self.builder = builder_class(template, target)
# Register as a delegate to the builder
self.builder.delegate = self
self.image = str(self.builder.image_id)
-
+
def build_image(self):
thread_name = "%s.build_image()" % (self.builder.image_id, )
# using args to pass the method we want to call on the target object.
self._builder_thread = Thread(target = self.builder, name=thread_name, args=('build_image'))
self._builder_thread.start()
-
+
def push_image(self, image_id, provider, credentials):
thread_name = "%s.push_image()" % (image_id, )
# using args to pass the method we want to call on the target object.
kwargs = dict(image_id=image_id, provider=provider, credentials=credentials)
self._builder_thread = Thread(target = self.builder, name=thread_name, args=('push_image'), kwargs=kwargs)
self._builder_thread.start()
-
+
def abort(self):
self.builder.abort()
-
+
# Builder delegate methods
def builder_did_update_status(self, builder, old_status, new_status):
self.status = new_status
@@ -180,11 +180,11 @@ class BuildAdaptor(object):
event.new_status = str(new_status)
event.old_status = str(old_status)
agent.session.raiseEvent(data=event, severity=4)
-
+
if(new_status == "COMPLETED"):
agent.deregister(self.qmf_object)
-
-
+
+
def builder_did_update_percentage(self, builder, original_percentage, new_percentage):
self.percent_complete = new_percentage
# FIXME: sloranz - I should be able to get the agent from the qmf_object this is a workaround...
@@ -196,7 +196,7 @@ class BuildAdaptor(object):
event.event = "PERCENTAGE"
event.percent_complete = new_percentage
agent.session.raiseEvent(data=event, severity=4)
-
+
# if __name__ == '__main__':
# unittest.main()
diff --git a/imagefactory/qmfagent/ImageFactory.py b/imagefactory/qmfagent/ImageFactory.py
index 7e0eab1..a9a2c71 100644
--- a/imagefactory/qmfagent/ImageFactory.py
+++ b/imagefactory/qmfagent/ImageFactory.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -26,7 +26,7 @@ from imagefactory.ApplicationConfiguration import ApplicationConfiguration
class ImageFactory(object):
instance = None
-
+
# QMF schema for ImageFactory
qmf_schema = Schema(SCHEMA_TYPE_DATA, "com.redhat.imagefactory", "ImageFactory")
_build_image_method = SchemaMethod("build_image", desc="Build a new image")
@@ -40,7 +40,7 @@ class ImageFactory(object):
_push_image_method.addArgument(SchemaProperty("credentials", SCHEMA_DATA_STRING, direction=DIR_IN))
_push_image_method.addArgument(SchemaProperty("build_adaptor", SCHEMA_DATA_MAP, direction=DIR_OUT))
qmf_schema.addMethod(_push_image_method)
-
+
## Properties
def qmf_object():
doc = "The qmf_object property."
@@ -52,21 +52,21 @@ class ImageFactory(object):
del self._qmf_object
return locals()
qmf_object = property(**qmf_object())
-
-
+
+
def __new__(cls, *p, **k):
if cls.instance is None:
cls.instance = object.__new__(cls, *p, **k)
return cls.instance
-
+
def __init__(self):
self.qmf_object = Data(ImageFactory.qmf_schema)
-
+
def build_image(self,template,target):
build_adaptor = BuildAdaptor.BuildAdaptor(template,target)
build_adaptor.build_image()
return build_adaptor
-
+
def push_image(self,image_id, provider, credentials):
base_url = ApplicationConfiguration().configuration['warehouse']
if (base_url):
@@ -81,4 +81,3 @@ class ImageFactory(object):
raise RuntimeError("Could not retrieve template (%s) or target (%s) from %s/%s" % (template, target, base_url, image_id))
else:
raise RuntimeError("No image warehouse found!")
-
diff --git a/imagefactory/qmfagent/ImageFactoryAgent.py b/imagefactory/qmfagent/ImageFactoryAgent.py
index bc4b501..fbb77e3 100644
--- a/imagefactory/qmfagent/ImageFactoryAgent.py
+++ b/imagefactory/qmfagent/ImageFactoryAgent.py
@@ -1,14 +1,14 @@
-# Copyright (C) 2010 Red Hat, Inc.
-#
+# 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 = {}
@@ -71,25 +71,25 @@ class ImageFactoryAgent(AgentHandler):
self.image_factory = ImageFactory()
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)
-
+
if (addr == self.image_factory_addr):
target_obj = self.image_factory
elif (repr(addr) in self.managedObjects):
target_obj = self.managedObjects[repr(addr)]
-
+
try:
result = getattr(target_obj, methodName)(**args)
except Exception, e:
self.log.exception(e)
self.session.raiseException(handle, "Exception: %s %s" % (repr(e), str(e)))
-
+
if (addr == self.image_factory_addr):
build_adaptor_instance_name = "build_adaptor-%s" % (result.builder.image_id, )
qmf_object_addr = self.session.addData(result.qmf_object, build_adaptor_instance_name, persistent=True)
@@ -107,7 +107,7 @@ class ImageFactoryAgent(AgentHandler):
else:
handle.addReturnArgument("result", repr(result))
self.session.methodSuccess(handle)
-
+
def shutdown(self):
"""
Clean up the session and connection. Cancel the running thread.
@@ -120,7 +120,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.
@@ -132,9 +132,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 c3ccac0..6ae02d2 100755
--- a/imgfac.py
+++ b/imgfac.py
@@ -1,17 +1,17 @@
#!/usr/bin/env python
# encoding: utf-8
-# Copyright (C) 2010 Red Hat, Inc.
-#
+# 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,
@@ -27,7 +27,7 @@ from imagefactory.qmfagent.ImageFactoryAgent import *
class Application(object):
instance = None
-
+
def qmf_agent():
doc = "The qmf_agent property."
def fget(self):
@@ -38,26 +38,26 @@ class Application(object):
del self._qmf_agent
return locals()
qmf_agent = property(**qmf_agent())
-
-
+
+
def __new__(cls, *p, **k):
if cls.instance is None:
cls.instance = object.__new__(cls, *p, **k)
return cls.instance
-
+
def __init__(self):
- super(Application, self).__init__()
+ super(Application, self).__init__()
logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)s %(name)s pid(%(process)d) Message: %(message)s', filename='/var/log/imagefactory.log')
signal.signal(signal.SIGTERM, self.signal_handler)
self.app_config = ApplicationConfiguration().configuration
-
+
def setup_logging(self):
logging.basicConfig(level=logging.WARNING, format='%(asctime)s %(levelname)s %(name)s pid(%(process)d) Message: %(message)s', filename='/var/log/imagefactory.log')
if (self.app_config['debug']):
logging.getLogger('').setLevel(logging.DEBUG)
elif (self.app_config['verbose']):
logging.getLogger('').setLevel(logging.INFO)
-
+
def signal_handler(self, signum, stack):
"""docstring for sigterm_handler"""
if (signum == signal.SIGTERM):
@@ -65,19 +65,19 @@ class Application(object):
if (self.qmf_agent):
self.qmf_agent.shutdown()
sys.exit(0)
-
-
+
+
# TODO: (redmine 273) - add code here to set the user:group we're running as and drop privileges
def daemonize(self): #based on Python recipe 278731
UMASK = 0
WORKING_DIRECTORY = '/'
IO_REDIRECT = os.devnull
-
+
try:
pid = os.fork()
except OSError, e:
raise Exception, "%s [%d]" % (e.strerror, e.errno)
-
+
if (pid == 0):
os.setsid()
signal.signal(signal.SIGHUP, signal.SIG_IGN)
@@ -85,7 +85,7 @@ class Application(object):
pid = os.fork()
except OSError, e:
raise Exception, "%s [%d]" % (e.strerror, e.errno)
-
+
if (pid == 0):
os.chdir(WORKING_DIRECTORY)
os.umask(UMASK)
@@ -93,30 +93,30 @@ class Application(object):
os._exit(0)
else:
os._exit(0)
-
+
for file_descriptor in range(0, 2): # close stdin, stdout, stderr
try:
os.close(file_descriptor)
except OSError:
pass # The file descriptor wasn't open to begin with, just ignore
-
+
os.open(IO_REDIRECT, os.O_RDWR)
os.dup2(0, 1)
os.dup2(0, 2)
-
+
return(True)
-
-
+
+
def main(self):
if (self.app_config['qmf']):
if (not self.app_config['foreground']):
self.daemonize()
self.setup_logging()
logging.info("Launching daemon...")
-
+
self.qmf_agent = ImageFactoryAgent(self.app_config['broker'])
self.qmf_agent.run()
-
+
if __name__ == "__main__":
diff --git a/tests/builders/testBaseBuilder.py b/tests/builders/testBaseBuilder.py
index b8e4061..d40a041 100644
--- a/tests/builders/testBaseBuilder.py
+++ b/tests/builders/testBaseBuilder.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -31,100 +31,100 @@ class TestBaseBuilder(unittest.TestCase):
self.builder = BaseBuilder()
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(BaseBuilder())
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/testMockBuilder.py b/tests/builders/testMockBuilder.py
index 7dc71d2..104bc5c 100644
--- a/tests/builders/testMockBuilder.py
+++ b/tests/builders/testMockBuilder.py
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -30,24 +30,24 @@ class TestMockBuilder(unittest.TestCase):
self.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.assertEqual(self.builder.template, self.template)
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/qmfagent/testBuildAdaptor.py b/tests/qmfagent/testBuildAdaptor.py
index 01be57f..df75c9a 100644
--- a/tests/qmfagent/testBuildAdaptor.py
+++ b/tests/qmfagent/testBuildAdaptor.py
@@ -1,14 +1,14 @@
-# Copyright (C) 2010 Red Hat, Inc.
-#
+# 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")
expected_schema_methods = dict(abort=())
@@ -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(self.tdl_string, "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 af9d9b6..a9e36ad 100644
--- a/tests/qmfagent/testImageFactory.py
+++ b/tests/qmfagent/testImageFactory.py
@@ -1,14 +1,14 @@
-# Copyright (C) 2010 Red Hat, Inc.
-#
+# 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,10 +25,10 @@ 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')
pass
-
+
def tearDown(self):
pass
-
+
def testQMFSchemaDefinition(self):
expected_schema_methods = dict(build_image=("template", "target", "build_adaptor"), push_image=("image_id", "provider", "credentials", "build_adaptor"))
for schema_method in ImageFactory.qmf_schema.getMethods():
@@ -36,16 +36,16 @@ class TestImageFactory(unittest.TestCase):
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()
self.assertIs(image_factory_one, image_factory_two)
-
+
# def testClassDefinition(self):
# pass
#
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/tests/qmfagent/testImageFactoryAgent.py b/tests/qmfagent/testImageFactoryAgent.py
index 7345fa6..14e503e 100644
--- a/tests/qmfagent/testImageFactoryAgent.py
+++ b/tests/qmfagent/testImageFactoryAgent.py
@@ -1,14 +1,14 @@
-# Copyright (C) 2010 Red Hat, Inc.
-#
+# 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,
@@ -39,7 +39,7 @@ class TestImageFactoryAgent(unittest.TestCase):
self.console = MockConsole(self.console_session)
self.console.start()
time.sleep(5) # Give the agent some time to show up. raise this value testQueries fails to find the agent.
-
+
def tearDown(self):
del self.expected_state_transitions
self.console.cancel()
@@ -50,7 +50,7 @@ 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 that the agent registered and consoles can see it.
@@ -65,7 +65,7 @@ class TestImageFactoryAgent(unittest.TestCase):
self.assertIsNotNone(self.console.build_adaptor_addr_str)
except AttributeError:
self.fail("build_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.assertGreater(self.console.event_count, len(self.expected_state_transitions))
@@ -78,30 +78,30 @@ class TestImageFactoryAgent(unittest.TestCase):
self.assertEqual(self.console.build_adaptor_addr_str, properties["addr"])
self.assertEqual(self.expected_state_transitions[index][0],properties["old_status"])
self.assertEqual(self.expected_state_transitions[index][1],properties["new_status"])
-
+
class MockConsole(ConsoleHandler):
def __init__(self, consoleSession):
super(MockConsole, self).__init__(consoleSession)
self.status_events = []
self.event_count = 0
-
+
def agentAdded(self, agent):
self.agent = agent
factories = agent.query("{class:ImageFactory, package:'com.redhat.imagefactory'}")
response = factories[0].build_image("<template></template>", "mock")
self.build_adaptor_addr_str = response["build_adaptor"]
-
+
def agentDeleted(self, agent, reason):
self.agent = None
self.reason_for_missing_agent = reason
-
+
def eventRaised(self, agent, data, timestamp, severity):
if(data.getProperties()["event"] == "STATUS"):
self.status_events.append(dict(agent=agent, data=data, 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 f87f93c..2f972c5 100644
--- a/tests/testApplicationConfiguration.py
+++ b/tests/testApplicationConfiguration.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# encoding: utf-8
-# Copyright (C) 2010 Red Hat, Inc.
+# 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
@@ -28,24 +28,24 @@ class TestApplicationConfiguration(unittest.TestCase):
self.arguments = self.app_config.arguments
self.configuration = self.app_config.configuration
self.defaults = dict(verbose=False, debug=False, foreground=False, config="/etc/imagefactory.conf", output="/tmp", qmf=False, broker="localhost", warehouse=None, template=None)
-
+
def tearDown(self):
del self.app_config
del self.arguments
del self.configuration
del self.defaults
-
+
def testSingleton(self):
self.assertIs(ApplicationConfiguration(), self.app_config)
-
+
def testArgumentDefaults(self):
self.assertIsNotNone(self.arguments)
for key in self.defaults:
self.assertEqual(getattr(self.arguments, key), self.defaults[key])
-
+
def testConfigurationDictionaryDefaults(self):
self.assertIsNotNone(self.configuration)
self.assertDictContainsSubset(self.defaults, self.configuration)
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
--
1.7.4
13 years, 1 month
[PATCH] Use specfic gems version, so that 'rake gems:install' doesn't pull in incompatible gems
by Richard Su
---
src/config/environments/cucumber.rb | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/config/environments/cucumber.rb b/src/config/environments/cucumber.rb
index 1e4a75d..c1bd610 100644
--- a/src/config/environments/cucumber.rb
+++ b/src/config/environments/cucumber.rb
@@ -21,9 +21,9 @@ config.action_controller.allow_forgery_protection = false
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
-config.gem 'cucumber-rails', :lib => false, :version => '>=0.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber-rails'))
-config.gem 'database_cleaner', :lib => false, :version => '>=0.5.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/database_cleaner'))
-config.gem 'webrat', :lib => false, :version => '>=0.7.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/webrat'))
-config.gem 'rspec', :lib => false, :version => '>=1.3.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec'))
-config.gem 'rspec-rails', :lib => false, :version => '>=1.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails'))
-config.gem "factory_girl", :lib => "factory_girl", :version => ">=1.3.1"
+config.gem 'cucumber-rails', :lib => false, :version => '~>0.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber-rails'))
+config.gem 'database_cleaner', :lib => false, :version => '~>0.5.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/database_cleaner'))
+config.gem 'webrat', :lib => false, :version => '~>0.7.3' unless File.directory?(File.join(Rails.root, 'vendor/plugins/webrat'))
+config.gem 'rspec', :lib => false, :version => '~>1.3.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec'))
+config.gem 'rspec-rails', :lib => false, :version => '~>1.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails'))
+config.gem "factory_girl", :lib => "factory_girl", :version => "~>1.3.1"
--
1.7.4
13 years, 1 month
[PATCH conductor] Modify cucumber gems configuration
by Richard Su
Specifically use rspec v 1.3.0 and rspec v 1.3.2, otherwise install will pull latest version that will require rails 3.0
---
src/config/environments/cucumber.rb | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/config/environments/cucumber.rb b/src/config/environments/cucumber.rb
index 1e4a75d..83932a5 100644
--- a/src/config/environments/cucumber.rb
+++ b/src/config/environments/cucumber.rb
@@ -24,6 +24,6 @@ config.action_mailer.delivery_method = :test
config.gem 'cucumber-rails', :lib => false, :version => '>=0.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber-rails'))
config.gem 'database_cleaner', :lib => false, :version => '>=0.5.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/database_cleaner'))
config.gem 'webrat', :lib => false, :version => '>=0.7.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/webrat'))
-config.gem 'rspec', :lib => false, :version => '>=1.3.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec'))
-config.gem 'rspec-rails', :lib => false, :version => '>=1.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails'))
+config.gem 'rspec', :lib => false, :version => '=1.3.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec'))
+config.gem 'rspec-rails', :lib => false, :version => '=1.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails'))
config.gem "factory_girl", :lib => "factory_girl", :version => ">=1.3.1"
--
1.7.4
13 years, 1 month
[PATCH] Rename aggregator -> conductor in condormatic.
by Chris Lalancette
The mass rename unfortunately forgot to fix condormatic,
which means the wrong provider classads were being generated.
Fix that here.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/app/util/condormatic.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/app/util/condormatic.rb b/src/app/util/condormatic.rb
index 80040b3..e62600b 100644
--- a/src/app/util/condormatic.rb
+++ b/src/app/util/condormatic.rb
@@ -235,7 +235,7 @@ def condormatic_classads_sync
pipe.puts 'MyType="Machine"'
pipe.puts 'Requirements=true'
pipe.puts "\n# Stuff needed to match:"
- pipe.puts "hardwareprofile=\"#{hwp.aggregator_hardware_profiles[0].id}\""
+ pipe.puts "hardwareprofile=\"#{hwp.conductor_hardware_profiles[0].id}\""
pipe.puts "image=\"#{provider_image.image.template.id}\""
pipe.puts "realm=\"#{realm.frontend_realms[0].id}\""
pipe.puts "\n# Backend info to complete this job:"
--
1.7.4
13 years, 2 months
[PATCH] Task #433 Create UI to show which providers an image has been uploaded to
by Richard Su
Renamed "Images" tab to "Builds"
Table columns now matches cloud-engine-templates-details-images.png mockup.
Table shows builds that have been completed and uploaded, and additional
providers that a completed build can be uploaded to. The additional provider's
provider type would have to match the build's target.
Note the Arch column may be redundant because the Architecture is specified
per template and not per build.
---
.../controllers/image_factory/builds_controller.rb | 2 +-
.../image_factory/templates_controller.rb | 27 +++++++++++++----
src/app/views/image_factory/templates/_builds.haml | 31 ++++++++++++++++++++
src/app/views/image_factory/templates/_images.haml | 20 -------------
src/features/step_definitions/template_steps.rb | 6 +++-
src/features/support/paths.rb | 2 +-
src/features/template.feature | 13 ++++++++
src/spec/factories/provider.rb | 8 +++++
8 files changed, 79 insertions(+), 30 deletions(-)
create mode 100644 src/app/views/image_factory/templates/_builds.haml
delete mode 100644 src/app/views/image_factory/templates/_images.haml
diff --git a/src/app/controllers/image_factory/builds_controller.rb b/src/app/controllers/image_factory/builds_controller.rb
index 13cfd7b..9b83bd7 100644
--- a/src/app/controllers/image_factory/builds_controller.rb
+++ b/src/app/controllers/image_factory/builds_controller.rb
@@ -37,7 +37,7 @@ class ImageFactory::BuildsController < ApplicationController
end
flash[:warning] = 'Warning: ' + warnings.join unless warnings.empty?
if errors.empty?
- redirect_to image_factory_template_path(@tpl, :details_tab => 'images')
+ redirect_to image_factory_template_path(@tpl, :details_tab => 'builds')
else
flash_error('Error while trying to build image', errors)
render :action => 'new'
diff --git a/src/app/controllers/image_factory/templates_controller.rb b/src/app/controllers/image_factory/templates_controller.rb
index f4ab91d..c79cdce 100644
--- a/src/app/controllers/image_factory/templates_controller.rb
+++ b/src/app/controllers/image_factory/templates_controller.rb
@@ -25,9 +25,9 @@ class ImageFactory::TemplatesController < ApplicationController
@tpl = Template.find(params[:id])
require_privilege(Privilege::VIEW, @tpl)
@url_params = params.clone
- @tab_captions = ['Properties', 'Images']
+ @tab_captions = ['Properties', 'Builds']
@details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab]
- load_images(@tpl) if @details_tab == 'images'
+ load_images(@tpl) if @details_tab == 'builds'
respond_to do |format|
format.js do
if @url_params.delete :details_pane
@@ -196,12 +196,26 @@ class ImageFactory::TemplatesController < ApplicationController
def load_images(tpl)
@images_header = [
- {:name => 'NAME', :sort_attr => 'templates.name'},
- {:name => 'OS', :sort_attr => 'templates.platform'},
- {:name => 'VERSION', :sort_attr => 'templates.platform_version'},
{:name => 'ARCH', :sort_attr => 'templates.architecture'},
+ {:name => 'PROVIDER', :sort_attr => 'provider'},
{:name => 'STATUS', :sort_attr => 'status'},
- ]
+ {:name => 'UPLOADED?', :sort_attr => 'images.uploaded'},
+ ]
+
+ @imaged_provider_types = {}
+ tpl.images.each do |img|
+ img.provider_images.each do |pimg|
+ @imaged_provider_types[pimg.provider_id] = img.target
+ end
+ end
+
+ @providers_not_uploaded = Provider.find_all_by_provider_type((a)imaged_provider_types.keys.uniq)
+ @providers_not_uploaded.each do |provider|
+ if @imaged_provider_types.has_key?(provider.id)
+ @providers_not_uploaded.delete(provider)
+ end
+ end
+
@images = tpl.images
end
@@ -283,4 +297,3 @@ class ImageFactory::TemplatesController < ApplicationController
end
end
-
diff --git a/src/app/views/image_factory/templates/_builds.haml b/src/app/views/image_factory/templates/_builds.haml
new file mode 100644
index 0000000..a9822f0
--- /dev/null
+++ b/src/app/views/image_factory/templates/_builds.haml
@@ -0,0 +1,31 @@
+Builds for
+= @tpl.platform
+= @tpl.platform_version
+, template "#{(a)tpl.name}"
+
+- form_tag :action => "" do
+ /= restful_submit_tag "Cancel Job", :name => "job_details", :disabled => true, :class => "icon"
+ /= restful_submit_tag "Show Job Details", :name => "job_details", :disabled => true, :class => "icon"
+ /= restful_submit_tag "Show Job Log", :name => "job_log", :disabled => true, :class => "icon"
+ /= restful_submit_tag "Clear Job History", :name => "job_history", :disabled => true, :class => "icon"
+
+ %table
+ = sortable_table_header(@images_header)
+ %tbody
+ - if @images.empty?
+ %tr
+ %td{:colspan => 5} No Builds
+ - else
+ - @images.each do |img|
+ - img.provider_images.each do |pimg|
+ %tr
+ %td= img.template.architecture
+ %td= pimg.provider.nil? ? '' : pimg.provider.name
+ %td= img.status
+ %td= pimg.uploaded? ? 'yes' : 'no'
+ - @providers_not_uploaded.each do |provider|
+ %tr
+ %td= @tpl.architecture
+ %td= provider.name
+ %td= img.status
+ %td no
\ No newline at end of file
diff --git a/src/app/views/image_factory/templates/_images.haml b/src/app/views/image_factory/templates/_images.haml
deleted file mode 100644
index 3fb1046..0000000
--- a/src/app/views/image_factory/templates/_images.haml
+++ /dev/null
@@ -1,20 +0,0 @@
-- form_tag :action => "" do
- /= restful_submit_tag "Cancel Job", :name => "job_details", :disabled => true, :class => "icon"
- /= restful_submit_tag "Show Job Details", :name => "job_details", :disabled => true, :class => "icon"
- /= restful_submit_tag "Show Job Log", :name => "job_log", :disabled => true, :class => "icon"
- /= restful_submit_tag "Clear Job History", :name => "job_history", :disabled => true, :class => "icon"
-
- %table
- = sortable_table_header(@images_header)
- %tbody
- - if @images.empty?
- %tr
- %td{:colspan => 5} No Images
- - else
- - @images.each do |img|
- %tr
- %td= img.template.name
- %td= img.template.platform
- %td= img.template.platform_version
- %td= img.template.architecture
- %td= img.status
diff --git a/src/features/step_definitions/template_steps.rb b/src/features/step_definitions/template_steps.rb
index 921e47f..a28f255 100644
--- a/src/features/step_definitions/template_steps.rb
+++ b/src/features/step_definitions/template_steps.rb
@@ -91,7 +91,6 @@ end
When /^I choose this template$/ do
click_link((a)template.name)
end
-
Given /^there is Amazon AWS provider account$/ do
account = Factory.build(:ec2_provider_account)
account.save!
@@ -101,6 +100,11 @@ Given /^there is Amazon AWS build for this template$/ do
Image.build(@template, Provider::AWS)
end
+Given /^there is Amazon AWS provider with no builds$/ do
+ provider = Factory.build(:ec2_provider_no_builds)
+ provider.save!
+end
+
Given /^there is an imported template$/ do
@template = Factory.build :template, :name => name, :imported => true
@template.save!
diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb
index 0633aca..4ec1ed8 100644
--- a/src/features/support/paths.rb
+++ b/src/features/support/paths.rb
@@ -78,7 +78,7 @@ module NavigationHelpers
url_for new_build_path
when /the template builds page/
- url_for image_factory_template_path(@template, :details_tab => 'images')
+ url_for image_factory_template_path(@template, :details_tab => 'builds')
when /the templates page/
templates_path
diff --git a/src/features/template.feature b/src/features/template.feature
index e0e58d4..58b7fe3 100644
--- a/src/features/template.feature
+++ b/src/features/template.feature
@@ -105,6 +105,19 @@ Feature: Manage Templates
# test that we see a collection (collections are loaded by default)
And I should see an input "conductor"
+ Scenario: See upload status
+ Given there is a "mock1" template
+ And there is Amazon AWS provider account
+ And there is Amazon AWS build for this template
+ And there is Amazon AWS provider with no builds
+ And I am on the image factory templates page
+ When I choose this template
+ And I follow "Builds"
+ Then I should see the following:
+ | ARCH | PROVIDERS | STATUS | UPLOADED? |
+ | x86_64 | amazon-ec2 | queued | no |
+ | x86_64 | amazon-ec2-no-builds | queued | no |
+
Scenario: Build template
Given there is a "mock1" template
And there is Amazon AWS provider account
diff --git a/src/spec/factories/provider.rb b/src/spec/factories/provider.rb
index f6288dc..9d3eda8 100644
--- a/src/spec/factories/provider.rb
+++ b/src/spec/factories/provider.rb
@@ -25,3 +25,11 @@ Factory.define :ec2_provider, :parent => :provider do |p|
p.hardware_profiles { |hp| [hp.association(:ec2_hwp1)] }
p.after_create { |p| p.realms << Factory(:realm4, :provider => p) }
end
+
+Factory.define :ec2_provider_no_builds, :parent => :provider do |p|
+ p.name 'amazon-ec2-no-builds'
+ p.provider_type '1'
+ p.url 'http://localhost:3002/api'
+ p.hardware_profiles { |hp| [hp.association(:ec2_hwp1)] }
+ p.after_create { |p| p.realms << Factory(:realm4, :provider => p) }
+end
--
1.7.4
13 years, 2 months
[PATCH] Fix up the check for create_site_admin_user.
by Chris Lalancette
The database is named "conductor", not "aeolus".
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
recipes/aeolus_recipe/manifests/conductor.pp | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/recipes/aeolus_recipe/manifests/conductor.pp b/recipes/aeolus_recipe/manifests/conductor.pp
index 2c22d4f..701f224 100644
--- a/recipes/aeolus_recipe/manifests/conductor.pp
+++ b/recipes/aeolus_recipe/manifests/conductor.pp
@@ -227,14 +227,14 @@ define aeolus::site_admin($email="", $password="", $first_name="", $last_name=""
environment => "RAILS_ENV=production",
command => "/usr/bin/rake dc:create_user[${name}] email=${email} password=${password} first_name=${first_name} last_name=${last_name}",
logoutput => true,
- unless => "/usr/bin/test `psql aeolus aeolus -P tuples_only -c \"select count(*) from users where login = '${name}';\"` = \"1\"",
+ unless => "/usr/bin/test `psql conductor aeolus -P tuples_only -c \"select count(*) from users where login = '${name}';\"` = \"1\"",
require => Rails::Seed::Db["seed_aeolus_database"]}
exec{"grant_site_admin_privs":
cwd => '/usr/share/aeolus-conductor',
environment => "RAILS_ENV=production",
command => "/usr/bin/rake dc:site_admin[${name}]",
logoutput => true,
- unless => "/usr/bin/test `psql aeolus aeolus -P tuples_only -c \"select count(*) FROM roles INNER JOIN permissions ON (roles.id = permissions.role_id) INNER JOIN users ON (permissions.user_id = users.id) where roles.name = 'Administrator' AND users.login = '${name}';\"` = \"1\"",
+ unless => "/usr/bin/test `psql conductor aeolus -P tuples_only -c \"select count(*) FROM roles INNER JOIN permissions ON (roles.id = permissions.role_id) INNER JOIN users ON (permissions.user_id = users.id) where roles.name = 'Administrator' AND users.login = '${name}';\"` = \"1\"",
require => Exec[create_site_admin_user]}
}
--
1.7.4
13 years, 2 months
Rename patch PUSHED
by Mike Orazi
All,
I wanted to give everyone the heads up that the rename patch sets have
been pushed to the aeolus-conductor & configure git repos.
A few notes that I came across:
* database.yml is in .gitignore -- there are updates to database.pg, so
you likely want to copy those over, especially if you are either
building rpms or using the configure recipes to set up your production
environment, otherwise DB user/pass won't match.
* your app will be found at http://<your_host>/conductor
* I was able to test end-to-end manually and ran through both
rspec/cucumber tests locally.
This is a pretty pervasive change. While Mo, Chris, and I made every
effort to ensure the quality of the changes it is quite possible that a
few things slipped through the cracks. If you find an issue, feel free
to bring it up and we'll work on it.
Also my apologies to anyone with another patch that will have to be
rebased. There is really no good time to release a big change like
this, so we decided to push it fairly early in the sprint to give
everyone time to react and fix any issues that may arise.
Thanks,
Mike
13 years, 2 months