ACK
On Jun 15, 2011, at 7:02 AM, Mark McLoughlin wrote:
e.g.
$> imgfac.py --target-image ami-669f680f --image-desc
'<image><name>My Image</name></image>' --target ec2
--provider ec2-us-east-1
imports the specified AMI metadata into IWHD as a provider image.
---
imagefactory/ApplicationConfiguration.py | 4 ++
imagefactory/BuildDispatcher.py | 65 +++++++++++++++++++++++++----
imagefactory/ImageWarehouse.py | 19 ++++++++-
imgfac.py | 11 +++++-
4 files changed, 87 insertions(+), 12 deletions(-)
diff --git a/imagefactory/ApplicationConfiguration.py
b/imagefactory/ApplicationConfiguration.py
index 3b121b8..989f2bb 100644
--- a/imagefactory/ApplicationConfiguration.py
+++ b/imagefactory/ApplicationConfiguration.py
@@ -70,6 +70,10 @@ class ApplicationConfiguration(Singleton):
group_push.add_argument('--provider', action='append',
help='Cloud service providers to push the image (e.g. ec2-us-east-1, rackspace,
etc.)')
group_push.add_argument('--credentials', help='Cloud provider
credentials XML (i.e. <provider_credentials/> document)')
+ group_build = argparser.add_argument_group(title='Image importing',
description=cli_build_description)
+ group_build.add_argument('--target-image', help='Target specific
identifier for the image to import.')
+ group_build.add_argument('--image-desc', help='XML document
describing the imported image.')
+
group_warehouse = argparser.add_argument_group(title='Image Warehouse',
description=warehouse_description)
group_warehouse.add_argument('--warehouse',
default='http://localhost:9090/', help='URL of the warehouse location to store
images. (default: %(default)s)')
group_warehouse.add_argument('--image_bucket', help='Name of
warehouse bucket to look in images. (default: %(default)s)')
diff --git a/imagefactory/BuildDispatcher.py b/imagefactory/BuildDispatcher.py
index 5e1ac4b..2bc0014 100644
--- a/imagefactory/BuildDispatcher.py
+++ b/imagefactory/BuildDispatcher.py
@@ -30,13 +30,24 @@ class BuildDispatcher(Singleton):
def _singleton_init(self):
self.warehouse =
ImageWarehouse(ApplicationConfiguration().configuration['warehouse'])
+ def import_image(self, image_id, build_id, target_identifier, image_desc, target,
provider):
+ image_id = self._ensure_image(image_id, image_desc)
+ build_id = self._ensure_build(image_id, build_id)
+
+ target_image_id = self._ensure_target_image(build_id, target)
+ provider_image_id = self._ensure_provider_image(target_image_id, provider,
target_identifier)
+
+ self._commit_build(image_id, build_id)
+
+ return (image_id, build_id, target_image_id, provider_image_id)
+
def build_image_for_targets(self, image_id, build_id, template, targets, job_cls =
BuildJob, *args, **kwargs):
if image_id and not targets:
targets = self._targets_for_image_id(image_id)
template = self._load_template(image_id, build_id, template)
- image_id = self._ensure_image(image_id, template)
+ image_id = self._ensure_image_with_template(image_id, template)
build_id = self._ensure_build(image_id, build_id)
watcher = BuildWatcher(image_id, build_id, len(targets), self.warehouse)
@@ -75,23 +86,39 @@ class BuildDispatcher(Singleton):
return None
return nodes[0].content
- def _ensure_image(self, image_id, template):
- if image_id:
- return image_id
-
+ def _ensure_image_with_template(self, image_id, template):
name = self._xml_node(template.xml, '/template/name')
if name:
- image_xml = '<image><name>%s</name></image>'
% name
+ image_desc =
'<image><name>%s</name></image>' % name
else:
- image_xml = '</image>'
+ image_desc = '</image>'
+ return self._ensure_image(image_id, image_desc)
- return self.warehouse.store_image(None, image_xml)
+ def _ensure_image(self, image_id, image_desc):
+ if image_id:
+ return image_id
+ else:
+ return self.warehouse.store_image(None, image_desc)
def _ensure_build(self, image_id, build_id):
if build_id:
return build_id
return self.warehouse.store_build(None, dict(image = image_id))
+ def _ensure_target_image(self, build_id, target):
+ target_image_id = self._target_image_for_build_and_target(build_id, target)
+ if target_image_id:
+ return target_image_id
+ return self.warehouse.store_target_image(None, None, dict(build=build_id,
target=target))
+
+ def _ensure_provider_image(self, target_image_id, provider, target_identifier):
+ provider_image_id =
self._provider_image_for_target_image_and_provider(target_image_id, provider)
+ if provider_image_id:
+ self._set_provider_image_attr(provider_image_id,
'target_identifier', target_identifier)
+ else:
+ metadata = dict(target_image=target_image_id, provider=provider,
target_identifier=target_identifier)
+ return self.warehouse.create_provider_image(None, None, metadata)
+
def _load_template(self, image_id, build_id, template):
if not template:
if build_id:
@@ -100,12 +127,24 @@ class BuildDispatcher(Singleton):
template = self._template_for_image_id(image_id)
return Template(template)
+ def _commit_build(self, image_id, build_id):
+ parent_id = self._latest_build(image_id)
+ if parent_id:
+ self._set_build_parent(build_id, parent_id)
+ self._set_latest_build(image_id, build_id)
+
def _latest_build(self, image_id):
return self.warehouse.metadata_for_id_of_type(['latest_build'], image_id,
'image')['latest_build']
def _latest_unpushed(self, image_id):
return self.warehouse.metadata_for_id_of_type(['latest_unpushed'],
image_id, 'image')['latest_unpushed']
+ def _set_latest_build(self, image_id, build_id):
+ self.warehouse.set_metadata_for_id_of_type({'latest_build' : build_id},
image_id, 'image')
+
+ def _set_build_parent(self, build_id, parent_id):
+ self.warehouse.set_metadata_for_id_of_type({'parent' : parent_id},
build_id, 'build')
+
def _targets_for_build_id(self, build_id):
targets = []
for target_image_id in self._target_images_for_build(build_id):
@@ -122,7 +161,15 @@ class BuildDispatcher(Singleton):
return self.warehouse.query("target_image", "$build ==
\"%s\"" % (build_id,))
def _target_image_for_build_and_target(self, build_id, target):
- return self.warehouse.query("target_image", "$build ==
\"%s\" && $target == \"%s\"" % (build_id, target))[0]
+ results = self.warehouse.query("target_image", "$build ==
\"%s\" && $target == \"%s\"" % (build_id, target))
+ return results[0] if results else None
+
+ def _provider_image_for_target_image_and_provider(self, target_image_id, provider):
+ results = self.warehouse.query("provider_image", "$target_image
== \"%s\" && $provider == \"%s\"" % (target_image_id,
provider))
+ return results[0] if results else None
+
+ def _set_provider_image_attr(provider_image_id, attr, value):
+ self.warehouse.set_metadata_for_id_of_type({attr : value}, provider_image_id,
"provider_image")
def _template_for_target_image_id(self, target_image_id):
return self.warehouse.metadata_for_id_of_type(['template'],
target_image_id, 'target_image')['template']
diff --git a/imagefactory/ImageWarehouse.py b/imagefactory/ImageWarehouse.py
index 9fbd110..02504cd 100644
--- a/imagefactory/ImageWarehouse.py
+++ b/imagefactory/ImageWarehouse.py
@@ -193,8 +193,7 @@ class ImageWarehouse(object):
return build_id
- def store_target_image(self, target_image_id, image_file_path, metadata=None):
- object_url = self.__url_for_id_of_type(target_image_id,
"target_image")
+ def _upload_image_file(self, object_url, image_file_path):
try:
image_file = open(image_file_path)
@@ -212,12 +211,26 @@ class ImageWarehouse(object):
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_target_image(self, target_image_id, image_file_path, metadata=None):
+ if(not target_image_id):
+ target_image_id = str(uuid.uuid4())
+ object_url = self.__url_for_id_of_type(target_image_id,
"target_image")
+
+ if image_file_path:
+ self._upload_image_file(object_url, image_file_path)
+ else:
+ self._http_put(object_url)
+
meta_data = dict(uuid=target_image_id, object_type="target_image")
if(metadata):
meta_data.update(metadata)
self.set_metadata_for_object_at_url(meta_data, object_url)
+ return target_image_id
+
def create_provider_image(self, image_id, txt=None, metadata=None):
+ if(not image_id):
+ image_id = str(uuid.uuid4())
object_url = self.__url_for_id_of_type(image_id,
object_type="provider_image")
if(not txt):
if(metadata):
@@ -232,6 +245,8 @@ class ImageWarehouse(object):
meta_data.update(metadata)
self.set_metadata_for_object_at_url(meta_data, object_url)
+ return image_id
+
def store_template(self, template, template_id=None, metadata=None):
if(not template_id):
template_id = str(uuid.uuid4())
diff --git a/imgfac.py b/imgfac.py
index daa6e71..2a8f1dd 100755
--- a/imgfac.py
+++ b/imgfac.py
@@ -147,7 +147,16 @@ class Application(Singleton):
self.app_config['foreground'] = True
self.setup_logging()
- if (self.app_config['template'] and
self.app_config['target']) or (self.app_config['image'] and not
self.app_config['provider']):
+ if self.app_config['target_image'] and
self.app_config['target'] and self.app_config['provider']:
+ if len(self.app_config['target']) != 1:
+ print("Expect a single target, but '%s' supplied"
% (self.app_config['target'],))
+ sys.exit(1)
+ if len(self.app_config['provider']) != 1:
+ print("Expect a single provider, but '%s'
supplied" % (self.app_config['provider'],))
+ sys.exit(1)
+ image_ids =
BuildDispatcher().import_image(self.app_config['image'], None,
self.app_config['target_image'], self.app_config['image_desc'],
self.app_config['target'][0], self.app_config['provider'][0])
+ print("Imported target image ID %s as image %s" %
(self.app_config['target_image'], image_ids[0]))
+ elif (self.app_config['template'] and
self.app_config['target']) or (self.app_config['image'] and not
self.app_config['provider']):
dispatchers =
BuildDispatcher().build_image_for_targets(self.app_config['image'], None,
self.app_config['template'], self.app_config['target'])
for dispatcher in dispatchers:
print("Building build %s of image %s to target %s" %
(dispatcher.build_id, dispatcher.image_id, dispatcher.target))
--
1.7.4.4