<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.comp.lib.deltacloud.devel">
    <title>gmane.comp.lib.deltacloud.devel</title>
    <link>http://blog.gmane.org/gmane.comp.lib.deltacloud.devel</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3757"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3756"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3755"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3754"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3753"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3751"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3745"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3738"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3736"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3728"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3717"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3713"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3711"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3706"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3702"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3698"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3697"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3689"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3688"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3686"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3757">
    <title>Model X</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3757</link>
    <description>&lt;pre&gt;In case you didn't hear, Tesla revealed their upcoming model X
yesterday, looks pretty nice:
http://www.teslamotors.com/modelx

-j
_______________________________________________
deltacloud-devel mailing list
deltacloud-devel&amp;lt; at &amp;gt;lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/deltacloud-devel&lt;/pre&gt;</description>
    <dc:creator>Jason Guiditta</dc:creator>
    <dc:date>2012-02-10T20:00:01</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3756">
    <title>JIRA DTACLOUD-127 - Valid Credentials Errors</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3756</link>
    <description>&lt;pre&gt;Gents

Unfortunately you've been away today.

I've some issues with the aforementioned JIRA.  The commit sent to me by 
fvollero:

https://git-wip-us.apache.org/repos/asf?p=deltacloud.git;a=commit;h=2fbc147f9e3041b19f2c89e4d222ba2185486405

does not solve the JIRA.  It only addresses the issue in EC2 Driver.  
This would suffice for the conductor BZ but this really should be fixed 
across the board.

Another fundamental issue is that the Deltacloud Client (ruby) does not 
properly support HTTP Errors.

We at least need the valid_credentials method to properly handle any 
HTTP Errors returned by the server.  But I think its worth noting though 
that properly handling errors really needs to implemented across the 
client as a whole.

I've created a patch for conductor addressing the original BZ: 
https://bugzilla.redhat.com/show_bug.cgi?id=753880 this will fix the BZ 
once the changes are in the client.

I've added some comments to the JIRA explaining the issue with the 
commit and a suggestion on how to handle http errors.

Could you guys let me know how this goes.

Thanks gents

Martyn


_______________________________________________
deltacloud-devel mailing list
deltacloud-devel&amp;lt; at &amp;gt;lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/deltacloud-devel&lt;/pre&gt;</description>
    <dc:creator>Martyn Taylor</dc:creator>
    <dc:date>2012-02-06T17:54:19</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3755">
    <title>Deltacloud Android App</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3755</link>
    <description>&lt;pre&gt;Gentlemen.

After speaking to Michal and Justin.  It sounds like Deltacloud might be 
interested in importing the Android App I build for DC into the DC project.

You guys are free to take it.

It's here: https://github.com/mtaylor/MobileCloudController

Just give me a few days to author the code before you pull it.

Regards

Martyn
_______________________________________________
deltacloud-devel mailing list
deltacloud-devel&amp;lt; at &amp;gt;lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/deltacloud-devel&lt;/pre&gt;</description>
    <dc:creator>Martyn Taylor</dc:creator>
    <dc:date>2012-02-02T14:46:18</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3754">
    <title>Android Deltacloud App</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3754</link>
    <description>&lt;pre&gt;Hi people,

I wrote a native Deltacloud Android App a while back but didn't get 
round to sending it out, I thought now is as good of a time as any to 
get it out there.

You can download the app from here: 
http://martyntaylor.fedorapeople.org/dcdroid.apk

Please check it out, there are one or two minor issues atm.  But all in 
all it does the job.  Please drop me aline if people have 
suggestions/bugs etc... I will get round to setting up a Redmine/BZ 
project soon.

One Note: The app uses the older style "one DC Instance per provider" 
format (Since I wrote the Android client way before the newer format was 
introduced).

Also, I've only tested this on a handful of displays though I written it 
to be compatible with most (though it might not look so great).

Have fun

Martyn



_______________________________________________
deltacloud-devel mailing list
deltacloud-devel&amp;lt; at &amp;gt;lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/deltacloud-devel&lt;/pre&gt;</description>
    <dc:creator>Martyn Taylor</dc:creator>
    <dc:date>2011-11-30T13:01:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3753">
    <title>Can I run deltacloudd server in a differentphysical machine?</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3753</link>
    <description>&lt;pre&gt;Hello all!

I have confusion about deltacloudd deployment. I have three cloud
deployments. Can I access all of them via single installation of
deltacloudd?
For example: I have OpenNebula cloud controller in server A, OpenStack
cloud controller in server B and Eucalyptus in server C. Can I install
deltacloud server in server D and install &amp;amp; run deltacloudc client
from server E. If yes, should I install deltacloudd server in each
cloud controller server (A, B, C) or is it possible to install single
deltacloudd server and run it for all three clouds (with different
drivers)?

Kind regards,
Nodir.
_______________________________________________
deltacloud-devel mailing list
deltacloud-devel&amp;lt; at &amp;gt;lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/deltacloud-devel&lt;/pre&gt;</description>
    <dc:creator>Nodir Kodirov</dc:creator>
    <dc:date>2011-11-07T02:42:04</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3751">
    <title>aeolus-configure -p rhevm is not working inlatest rpms from testing</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3751</link>
    <description>&lt;pre&gt;https://bugzilla.redhat.com/show_bug.cgi?id=751113

_______________________________________________
deltacloud-devel mailing list
deltacloud-devel&amp;lt; at &amp;gt;lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/deltacloud-devel&lt;/pre&gt;</description>
    <dc:creator>wes hayutin</dc:creator>
    <dc:date>2011-11-03T15:00:01</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3745">
    <title>Condor Cloud Driver</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3745</link>
    <description>&lt;pre&gt;
Howdy Folks,

So Michal and I have been working on a Condor based cloud using
deltacloud as the front end API.  The code base can be found here:

http://git.fedorahosted.org/git/?p=condor-cloud.git

There are still some cleanups and testing to be done but I would like to
get this into Fedora 16 as a feature. I  am hoping you guys can take a
look and let me know if this is acceptable and what needs to be fixed to
make it so.

There are actually two parts to this project, one is the deltacloud
driver, which can be found under the deltacloud-condor-driver directory.
The rest deals with condor configuration and scripts.

I'm thinking I may name this project 'falcondor' as it seems unused and
more interesting :).

Thanks!

        Ian
&lt;/pre&gt;</description>
    <dc:creator>Ian Main</dc:creator>
    <dc:date>2011-07-08T20:06:44</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3738">
    <title>Post Installation: New HWP Model</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3738</link>
    <description>&lt;pre&gt;Gentlemen,

I've noticed a lot of chat around not being able to start instances.

For any of you who are not aware, you now *MUST create a HWP post installation (that matches some back end provider HWP) in order to start an instance.

Documentation for this is found here: http://www.aeolusproject.org/conductor-use.html
&lt;/pre&gt;</description>
    <dc:creator>Martyn Taylor</dc:creator>
    <dc:date>2011-03-14T16:16:17</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3736">
    <title>Timeout support in deltacloud-client</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3736</link>
    <description>&lt;pre&gt;Hi all,

I want to propose adding timeout capabilities to deltacloud-client. I'm 
seeing problems in Aeolus Conductor where a non-responding provider will 
hang indefinitely until Apache closes the connection. I think the fix is 
to allow deltacloud-client to raise an exception on timeouts instead of 
trying to do so each place Conductor calls out to a provider. (A good 
demonstration of this problem is to attempt to add a provider like 
'http://1.1.1.1:1234/api'.)

rest-client has support for two types of timeout: an 'open_timeout' when 
opening a connection, and a normal 'timeout' for an active connection: 
http://rdoc.info/github/adamwiggins/rest-client/master/RestClient/Resource

I will send a quick patch that adds these two timeouts to the 'request' 
method. I don't know the deltacloud-client code that well, so I'd 
appreciate it if someone could let me know if there is a better way of 
accomplishing this.

Best,
Matt
&lt;/pre&gt;</description>
    <dc:creator>Matt Wagner</dc:creator>
    <dc:date>2011-02-17T19:32:49</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3728">
    <title>Task #197 - Remove any logic forcing oneprovider only</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3728</link>
    <description>&lt;pre&gt;

This patchset contains not only code for task #197, but also it contains renaming model of CloudAccount to ProviderAccount, and all fixings, that they were needed for green tests and changes in next branch, while this patchset was written. You need to apply all patches to work it well, when you will make a review.
&lt;/pre&gt;</description>
    <dc:creator>jzigmund-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-27T15:37:48</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3717">
    <title>rename deltacloud-configure to aeolus-configure</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3717</link>
    <description>&lt;pre&gt;Renamed deltacloud to aeolus in the recipe and docs.
Also update subcomponents which have been renamed
  (aggregator to conductor, core to deltacloud)
&lt;/pre&gt;</description>
    <dc:creator>Mohammed Morsi</dc:creator>
    <dc:date>2011-01-20T02:45:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3713">
    <title>initial aeolus-configure ssl integration</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3713</link>
    <description>&lt;pre&gt;This patchset integrates ssl support for https and postgres
into the aeolus puppet recipe and configuration scripts
&lt;/pre&gt;</description>
    <dc:creator>Mohammed Morsi</dc:creator>
    <dc:date>2011-01-19T21:54:14</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3711">
    <title>[PATCH] refactored role/privilege model</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3711</link>
    <description>&lt;pre&gt;Privileges are now a combination of a base action and a target object type (i.e. "modify" on Pool instead of the flat string "pool_modify"). In addition, the modeling has changed -- instead of a privileges model that was only low-level privileges with an explicit mapping to roles, the privileges model now tracks the privileges assigned to each role, with no separate mapping table.

This will require a database reload as the seeds.rb required substantial changes in role/privilege loading

Signed-off-by: Scott Seago &amp;lt;sseago-H+wXaHxf7aLQT0dZR+AlfA&amp;lt; at &amp;gt;public.gmane.org&amp;gt;
---
 .../admin/provider_accounts_controller.rb          |   11 +-
 src/app/controllers/admin/providers_controller.rb  |   15 +-
 src/app/controllers/admin/settings_controller.rb   |   15 +--
 src/app/controllers/admin/users_controller.rb      |   32 +---
 src/app/controllers/application_controller.rb      |   11 +-
 src/app/controllers/builds_controller.rb           |   10 +-
 src/app/controllers/cloud_accounts_controller.rb   |   20 ++--
 src/app/controllers/dashboard_controller.rb        |   10 --
 .../controllers/hardware_profiles_controller.rb    |    1 -
 .../controllers/image_factory/builds_controller.rb |    8 +-
 .../image_factory/templates_controller.rb          |   66 ++++++---
 src/app/controllers/instances_controller.rb        |   12 +-
 src/app/controllers/permissions_controller.rb      |   14 +-
 src/app/controllers/pools_controller.rb            |   38 ++----
 src/app/controllers/providers_controller.rb        |   27 ++--
 src/app/controllers/quotas_controller.rb           |    8 +-
 .../controllers/resources/instances_controller.rb  |   10 +-
 src/app/controllers/resources/pools_controller.rb  |   15 +-
 src/app/controllers/settings_controller.rb         |   17 +--
 src/app/controllers/templates_controller.rb        |   50 ++++--
 src/app/controllers/users_controller.rb            |   79 ++++------
 src/app/models/cloud_account.rb                    |   21 +++
 src/app/models/instance.rb                         |   27 +++-
 src/app/models/permission.rb                       |    6 +
 src/app/models/permissioned_object.rb              |  136 +++++++---------
 src/app/models/privilege.rb                        |  168 +++++++++++++-------
 src/app/models/role.rb                             |    7 +-
 src/app/models/template.rb                         |    5 +
 src/app/services/application_service.rb            |   35 +++--
 src/app/views/admin/users/_form.haml               |    4 +-
 src/app/views/admin/users/edit.haml                |    2 +-
 src/app/views/dashboard/summary.haml               |   20 ++--
 src/app/views/layouts/_main_nav.html.erb           |    2 +-
 src/app/views/permissions/list.haml                |    6 +-
 src/app/views/pools/show.haml                      |    2 +-
 src/app/views/providers/accounts.haml              |    4 +-
 src/app/views/users/_form.haml                     |    4 +-
 src/app/views/users/edit.haml                      |    2 +-
 .../20110107000000_privilege_model_refactor.rb     |   53 ++++++
 src/db/seeds.rb                                    |  163 ++++++++------------
 src/features/support/custom.rb                     |    4 -
 src/features/support/hooks.rb                      |   17 --
 src/lib/tasks/cucumber.rake                        |    6 +-
 src/spec/controllers/instance_controller_spec.rb   |   12 +-
 src/spec/controllers/users_controller_spec.rb      |    7 -
 src/spec/factories/base_permission_object.rb       |    3 -
 src/spec/factories/metadata_object.rb              |   34 ----
 src/spec/factories/permission.rb                   |    8 +-
 src/spec/factories/pool.rb                         |    2 +-
 src/spec/factories/pool_family.rb                  |    2 +-
 src/spec/factories/user.rb                         |    5 +-
 src/spec/fixtures/base_permission_objects.yml      |    2 -
 src/spec/fixtures/privileges.yml                   |   43 -----
 src/spec/fixtures/roles.yml                        |   47 ------
 src/spec/models/metadata_object_spec.rb            |    2 +-
 src/spec/models/permission_spec.rb                 |   58 +++++++
 src/spec/models/pool_family_spec.rb                |    4 +-
 src/spec/services/registration_service_spec.rb     |   14 +--
 src/spec/spec_helper.rb                            |    2 +-
 59 files changed, 705 insertions(+), 703 deletions(-)
 create mode 100644 src/db/migrate/20110107000000_privilege_model_refactor.rb
 delete mode 100644 src/spec/factories/base_permission_object.rb
 delete mode 100644 src/spec/factories/metadata_object.rb
 delete mode 100644 src/spec/fixtures/base_permission_objects.yml
 delete mode 100644 src/spec/fixtures/privileges.yml
 delete mode 100644 src/spec/fixtures/roles.yml
 create mode 100644 src/spec/models/permission_spec.rb

diff --git a/src/app/controllers/admin/provider_accounts_controller.rb b/src/app/controllers/admin/provider_accounts_controller.rb
index 2c331f7..960f4f5 100644
--- a/src/app/controllers/admin/provider_accounts_controller.rb
+++ b/src/app/controllers/admin/provider_accounts_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -8,6 +8,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProviderAccountsController &amp;lt; ApplicationController
   def show
     &amp;lt; at &amp;gt;tab_captions = ['Properties', 'Credentials', 'History', 'Permissions']
     &amp;lt; at &amp;gt;account = CloudAccount.find(params[:id])
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;account)
     &amp;lt; at &amp;gt;details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab]
 
     if params.delete :test_account
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -34,7 +35,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProviderAccountsController &amp;lt; ApplicationController
 
   def create
     &amp;lt; at &amp;gt;provider = Provider.find(params[:provider_id])
-    require_privilege(Privilege::ACCOUNT_MODIFY, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_CREATE, CloudAccount, &amp;lt; at &amp;gt;provider)
 
     &amp;lt; at &amp;gt;providers = Provider.all
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.new(params[:cloud_account])
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -73,13 +74,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProviderAccountsController &amp;lt; ApplicationController
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.find(params[:id])
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;cloud_account.quota
     &amp;lt; at &amp;gt;provider = &amp;lt; at &amp;gt;cloud_account.provider
-    require_privilege(Privilege::ACCOUNT_MODIFY,&amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_MODIFY,&amp;lt; at &amp;gt;cloud_account)
   end
 
   def update
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.find(params[:id])
     &amp;lt; at &amp;gt;provider = &amp;lt; at &amp;gt;cloud_account.provider
-    require_privilege(Privilege::ACCOUNT_MODIFY, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_MODIFY,&amp;lt; at &amp;gt;cloud_account)
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;cloud_account.quota
 
     if params.delete :test_account
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -101,7 +102,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProviderAccountsController &amp;lt; ApplicationController
     if (not params[:accounts_selected]) or (params[:accounts_selected].length == 0)
       flash[:notice] = "You must select some accounts first."
     else
-      CloudAccount.destroy(params[:accounts_selected])
+      CloudAccount.find(params[:accounts_selected]).each do |account|
+        account.destroy if check_privilege(Privilege::ACTION_MODIFY, account)
+      end
     end
     redirect_to admin_provider_accounts_url
   end
diff --git a/src/app/controllers/admin/providers_controller.rb b/src/app/controllers/admin/providers_controller.rb
index aac2c1d..61a405b 100644
--- a/src/app/controllers/admin/providers_controller.rb
+++ b/src/app/controllers/admin/providers_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,19 +6,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProvidersController &amp;lt; ApplicationController
   end
 
   def new
-    require_privilege(Privilege::PROVIDER_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Provider)
     &amp;lt; at &amp;gt;provider = Provider.new
     kick_condor
   end
 
   def edit
     &amp;lt; at &amp;gt;provider = Provider.find_by_id(params[:id])
-    require_privilege(Privilege::PROVIDER_MODIFY, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;provider)
   end
 
   def show
     &amp;lt; at &amp;gt;provider = Provider.find(params[:id])
     &amp;lt; at &amp;gt;url_params = params.clone
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;provider)
     &amp;lt; at &amp;gt;tab_captions = ['Properties', 'HW Profiles', 'Realms', 'Provider Accounts', 'Services','History','Permissions']
     &amp;lt; at &amp;gt;details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab]
     respond_to do |format|
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,7 +34,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProvidersController &amp;lt; ApplicationController
   end
 
   def create
-    require_privilege(Privilege::PROVIDER_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Provider)
     &amp;lt; at &amp;gt;provider = Provider.new(params[:provider])
     if params[:test_connection]
       test_connection(&amp;lt; at &amp;gt;provider)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -52,8 +53,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProvidersController &amp;lt; ApplicationController
   end
 
   def update
-   require_privilege(Privilege::PROVIDER_MODIFY)
    &amp;lt; at &amp;gt;provider = Provider.find_by_id(params[:id])
+   require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;provider)
    previous_cloud_type = &amp;lt; at &amp;gt;provider.cloud_type
    &amp;lt; at &amp;gt;provider.update_attributes(params[:provider])
    if params[:test_connection]
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -77,7 +78,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProvidersController &amp;lt; ApplicationController
   end
 
   def multi_destroy
-    Provider.destroy(params[:provider_selected])
+    Provider.find(params[:provider_selected]).each do |provider|
+      provider.destroy if check_privilege(Privilege::ACTION_MODIFY, provider)
+    end
     redirect_to admin_providers_url
   end
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -97,7 +100,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::ProvidersController &amp;lt; ApplicationController
       &amp;lt; at &amp;gt;header = [{ :name =&amp;gt; "Provider name", :sort_attr =&amp;gt; :name },
                  { :name =&amp;gt; "Provider URL", :sort_attr =&amp;gt; :name }
       ]
-      &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_VIEW)
+      &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
       &amp;lt; at &amp;gt;url_params = params.clone
     end
 end
diff --git a/src/app/controllers/admin/settings_controller.rb b/src/app/controllers/admin/settings_controller.rb
index accf398..2b816d4 100644
--- a/src/app/controllers/admin/settings_controller.rb
+++ b/src/app/controllers/admin/settings_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,18 +6,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::SettingsController &amp;lt; ApplicationController
   KEYS = [SELF_SERVICE_DEFAULT_QUOTA]
 
   def self_service
-    if !is_admin?
-      raise PermissionError.new('You have insufficient privileges to perform action.')
-      return
-    end
+    require_privilege(Privilege::ACTION_MODIFY)
     &amp;lt; at &amp;gt;self_service_default_quota = MetadataObject.lookup(SELF_SERVICE_DEFAULT_QUOTA)
   end
 
   def general_settings
-    if !is_admin?
-      raise PermissionError.new('You have insufficient privileges to perform action.')
-      return
-    end
+    require_privilege(Privilege::ACTION_MODIFY)
   end
 
   def update
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -47,9 +41,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::SettingsController &amp;lt; ApplicationController
     redirect_to :action =&amp;gt; 'self_service'
   end
 
-  private
-  def is_admin?
-    is_admin = &amp;lt; at &amp;gt;current_user.permissions.collect { |p| p.role }.find { |r| r.name == "Administrator" }
-    return is_admin == nil ? false : true
-  end
 end
diff --git a/src/app/controllers/admin/users_controller.rb b/src/app/controllers/admin/users_controller.rb
index 0e854a9..4648da9 100644
--- a/src/app/controllers/admin/users_controller.rb
+++ b/src/app/controllers/admin/users_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,9 +1,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 class Admin::UsersController &amp;lt; ApplicationController
   before_filter :require_user
-  before_filter :only_admin, :only =&amp;gt; [:index, :multi_destroy]
   before_filter :load_users, :only =&amp;gt; [:index, :show]
 
   def new
+    require_privilege(Privilege::ACTION_CREATE, User) unless current_user.nil?
     &amp;lt; at &amp;gt;user = User.new
     &amp;lt; at &amp;gt;user.quota = Quota.new
   end
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -13,8 +13,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::UsersController &amp;lt; ApplicationController
       redirect_to :action =&amp;gt; 'new' and return
     end
 
-    # TODO: Shouldn't it be if current_user.nil? instead?
-    require_privilege(Privilege::USER_MODIFY) unless current_user.nil?
+    require_privilege(Privilege::ACTION_MODIFY, User) unless current_user.nil?
     &amp;lt; at &amp;gt;user = User.new(params[:user])
 
     &amp;lt; at &amp;gt;registration = RegistrationService.new(&amp;lt; at &amp;gt;user)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -34,6 +33,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::UsersController &amp;lt; ApplicationController
 
   def show
     &amp;lt; at &amp;gt;user = User.find_by_id(params[:id]) || current_user
+    require_privilege(Privilege::ACTION_VIEW, User) unless current_user == &amp;lt; at &amp;gt;user
     &amp;lt; at &amp;gt;quota_resources = &amp;lt; at &amp;gt;user.quota.quota_resources
 
     &amp;lt; at &amp;gt;url_params = params.clone
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -52,15 +52,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::UsersController &amp;lt; ApplicationController
 
   def edit
     &amp;lt; at &amp;gt;user = User.find_by_id(params[:id]) || current_user
-
-    if cannot_modify_different_user?(&amp;lt; at &amp;gt;user)
-      flash[:notice] = "Invalid Permission to perform this operation"
-      redirect_to dashboard_url and return
-    end
+    require_privilege(Privilege::ACTION_MODIFY, User) unless &amp;lt; at &amp;gt;user == current_user
   end
 
   def update
     &amp;lt; at &amp;gt;user = User.find_by_id(params[:id]) || current_user
+    require_privilege(Privilege::ACTION_MODIFY, User) unless &amp;lt; at &amp;gt;user == current_user
 
     if params[:commit] == "Reset"
       redirect_to edit_admin_user_url(&amp;lt; at &amp;gt;user) and return
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -68,20 +65,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::UsersController &amp;lt; ApplicationController
 
     redirect_to dashboard_url and return unless &amp;lt; at &amp;gt;user
 
-    if cannot_modify_different_user = cannot_modify_different_user?(&amp;lt; at &amp;gt;user)
-      flash[:notice] = "Invalid Permission to perform this operation"
-      redirect_to dashboard_url and return
-    end
-
     unless &amp;lt; at &amp;gt;user.update_attributes(params[:user])
       render :action =&amp;gt; 'edit' and return
     else
       flash[:notice] = "User updated!"
-      redirect_to cannot_modify_different_user ? dashboard_url : admin_users_url
+      redirect_to (&amp;lt; at &amp;gt;user == current_user) ? dashboard_url : admin_users_url
     end
   end
 
   def multi_destroy
+    require_privilege(Privilege::ACTION_MODIFY, User)
     User.destroy(params[:user_selected])
     redirect_to admin_users_url
   end
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -101,15 +94,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::UsersController &amp;lt; ApplicationController
     end
   end
 
-  def only_admin
-    unless current_user.permissions.collect { |p| p.role }.find { |r| r.name == "Administrator" }
-      flash[:notice] = "Invalid Permission to perform this operation"
-      redirect_to dashboard_url
-    end
-  end
-
-  def cannot_modify_different_user?(user)
-    user &amp;amp;&amp;amp; user != current_user &amp;amp;&amp;amp; !BasePermissionObject.general_permission_scope.can_modify_users(current_user)
-  end
-
 end
diff --git a/src/app/controllers/application_controller.rb b/src/app/controllers/application_controller.rb
index b77fe9c..b0386e0 100644
--- a/src/app/controllers/application_controller.rb
+++ b/src/app/controllers/application_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -60,13 +60,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ApplicationController &amp;lt; ActionController::Base
     'generic'
   end
 
-  perm_helper_string = ""
-  Privilege::FULL_PRIVILEGE_LIST.each do |privilege|
-    perm_helper_string += "def has_#{privilege}?(obj=&amp;lt; at &amp;gt;perm_obj); " +
-      "check_privilege(\"#{privilege}\", obj) end; "
-  end
-  master_helper_module.module_eval perm_helper_string
-
   helper_method :check_privilege
 
   protected
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -162,8 +155,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ApplicationController &amp;lt; ActionController::Base
 
   def get_nav_items
     if current_user.present?
-      &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_VIEW)
-      &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::POOL_VIEW)
+      &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
+      &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
     end
   end
 
diff --git a/src/app/controllers/builds_controller.rb b/src/app/controllers/builds_controller.rb
index 7cf0ad6..e205171 100644
--- a/src/app/controllers/builds_controller.rb
+++ b/src/app/controllers/builds_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,12 +1,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 class BuildsController &amp;lt; ApplicationController
-  before_filter [:require_user, :check_permission]
+  before_filter [:require_user]
 
   def section_id
     'build'
   end
 
   def index
-    require_privilege(Privilege::IMAGE_VIEW)
+    require_privilege(Privilege::ACTION_VIEW, Template)
     order = get_order('templates.name')
     &amp;lt; at &amp;gt;running_images = Image.all(:include =&amp;gt; :template, :conditions =&amp;gt; ['status IN (?)', Image::ACTIVE_STATES], :order =&amp;gt; order)
     &amp;lt; at &amp;gt;completed_images = Image.all(:include =&amp;gt; :template, :conditions =&amp;gt; {:status =&amp;gt; Image::STATE_COMPLETE}, :order =&amp;gt; order)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,6 +16,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class BuildsController &amp;lt; ApplicationController
   def new
     raise "select template to build" unless id = params[:template_id]
     &amp;lt; at &amp;gt;tpl = Template.find(id)
+    check_permission
     if &amp;lt; at &amp;gt;tpl.imported
       flash[:warning] = "Build imported template is not supported"
       redirect_to templates_path
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -30,6 +31,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class BuildsController &amp;lt; ApplicationController
     end
 
     &amp;lt; at &amp;gt;tpl = Template.find(params[:template_id])
+    check_permission
     &amp;lt; at &amp;gt;all_targets = Image.available_targets
 
     if params[:targets].blank?
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -60,9 +62,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class BuildsController &amp;lt; ApplicationController
   end
 
   def edit
+    # FIXME: is &amp;lt; at &amp;gt;tpl defined here? do we need check_permission here?
   end
 
   def update
+    # FIXME: is &amp;lt; at &amp;gt;tpl defined here? do we need check_permission here?
   end
 
   private
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -82,6 +86,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class BuildsController &amp;lt; ApplicationController
   end
 
   def check_permission
-    require_privilege(Privilege::IMAGE_MODIFY)
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;tpl)
   end
 end
diff --git a/src/app/controllers/cloud_accounts_controller.rb b/src/app/controllers/cloud_accounts_controller.rb
index 75a75d9..c2fe5e7 100644
--- a/src/app/controllers/cloud_accounts_controller.rb
+++ b/src/app/controllers/cloud_accounts_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -31,19 +31,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CloudAccountsController &amp;lt; ApplicationController
 
   def index
     &amp;lt; at &amp;gt;provider = Provider.find(params[:provider_id])
-    require_privilege(Privilege::ACCOUNT_VIEW, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_VIEW, CloudAccount, &amp;lt; at &amp;gt;provider)
   end
 
   def new
     &amp;lt; at &amp;gt;provider = Provider.find(params[:provider_id])
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.new
     &amp;lt; at &amp;gt;quota = Quota.new
-    require_privilege(Privilege::ACCOUNT_MODIFY, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_CREATE, CloudAccount, &amp;lt; at &amp;gt;provider)
   end
 
   def create
     &amp;lt; at &amp;gt;provider = Provider.find(params[:provider_id])
-    require_privilege(Privilege::ACCOUNT_MODIFY,&amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_CREATE, CloudAccount, &amp;lt; at &amp;gt;provider)
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.new(params[:cloud_account])
     &amp;lt; at &amp;gt;cloud_account.provider = &amp;lt; at &amp;gt;provider
     &amp;lt; at &amp;gt;cloud_account.quota = &amp;lt; at &amp;gt;quota = Quota.new
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -80,13 +80,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CloudAccountsController &amp;lt; ApplicationController
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.find(params[:id])
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;cloud_account.quota
     &amp;lt; at &amp;gt;provider = &amp;lt; at &amp;gt;cloud_account.provider
-    require_privilege(Privilege::ACCOUNT_MODIFY,&amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;cloud_account)
   end
 
   def update_accounts
     &amp;lt; at &amp;gt;provider = Provider.find(params[:provider][:id])
-    require_privilege(Privilege::ACCOUNT_MODIFY, &amp;lt; at &amp;gt;provider)
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_VIEW)
+    require_privilege(Privilege::ACTION_MODIFY, CloudAccount, &amp;lt; at &amp;gt;provider)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
 
     success = true
     &amp;lt; at &amp;gt;provider.cloud_accounts.each do |cloud_account|
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -130,7 +130,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CloudAccountsController &amp;lt; ApplicationController
   def update
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.find(params[:id])
     &amp;lt; at &amp;gt;provider = &amp;lt; at &amp;gt;cloud_account.provider
-    require_privilege(Privilege::ACCOUNT_MODIFY, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;cloud_account)
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;cloud_account.quota
 
     limit = params[:quota][:maximum_running_instances] if params[:quota]
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -145,7 +145,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CloudAccountsController &amp;lt; ApplicationController
 
   def key
     &amp;lt; at &amp;gt;cloud_account = CloudAccount.find(params[:id])
-    require_privilege(Privilege::ACCOUNT_MODIFY,&amp;lt; at &amp;gt;cloud_account.provider)
+    require_privilege(Privilege::ACTION_MODIFY,&amp;lt; at &amp;gt;cloud_account)
     unless &amp;lt; at &amp;gt;cloud_account.instance_key.nil?
       render :text =&amp;gt; &amp;lt; at &amp;gt;cloud_account.instance_key.pem
     end
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -154,7 +154,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CloudAccountsController &amp;lt; ApplicationController
   def destroy
     account = CloudAccount.find(params[:id])
     provider = account.provider
-    require_privilege(Privilege::ACCOUNT_MODIFY, provider)
+    require_privilege(Privilege::ACTION_MODIFY, account)
     if account.destroy
       flash[:notice] = "Cloud Account destroyed"
     else
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -176,6 +176,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CloudAccountsController &amp;lt; ApplicationController
   private
 
   def load_providers
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_VIEW)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
   end
 end
diff --git a/src/app/controllers/dashboard_controller.rb b/src/app/controllers/dashboard_controller.rb
index 8d37a12..5254dd7 100644
--- a/src/app/controllers/dashboard_controller.rb
+++ b/src/app/controllers/dashboard_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -70,16 +70,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class DashboardController &amp;lt; ApplicationController
     &amp;lt; at &amp;gt;cloud_accounts = CloudAccount.find(:all)
 
 
-    # Now need to check any permissions are set since default permission and pool
-    # may not be set for the admin user
-    if &amp;lt; at &amp;gt;current_user.permissions
-      # FIXME remove general role based permission check, replace w/
-      # more granular / per-permission-object permission checks on the
-      # dashboard in the future (here and in dashboard views)
-      &amp;lt; at &amp;gt;is_admin = &amp;lt; at &amp;gt;current_user.permissions.collect { |p| p.role }.
-                                find { |r| r.name == "Administrator" }
-    end
-
     render :action =&amp;gt; 'monitor'
   end
 
diff --git a/src/app/controllers/hardware_profiles_controller.rb b/src/app/controllers/hardware_profiles_controller.rb
index c3afae2..d18110c 100644
--- a/src/app/controllers/hardware_profiles_controller.rb
+++ b/src/app/controllers/hardware_profiles_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -23,7 +23,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfilesController &amp;lt; ApplicationController
 
   def index
     &amp;lt; at &amp;gt;hardware_profiles = HardwareProfile.find(:all)
-    #require_privilege(Privilege::PROVIDER_VIEW, &amp;lt; at &amp;gt;hardware_profile) ?
   end
 
   def new
diff --git a/src/app/controllers/image_factory/builds_controller.rb b/src/app/controllers/image_factory/builds_controller.rb
index 97bd32f..df9aba6 100644
--- a/src/app/controllers/image_factory/builds_controller.rb
+++ b/src/app/controllers/image_factory/builds_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,9 +1,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 class ImageFactory::BuildsController &amp;lt; ApplicationController
-  before_filter [:require_user, :check_permission]
+  before_filter [:require_user]
 
   def new
     raise "select template to build" unless id = params[:template_id]
     &amp;lt; at &amp;gt;tpl = Template.find(id)
+    check_permission
     if &amp;lt; at &amp;gt;tpl.imported
       flash[:warning] = "Build imported template is not supported"
       redirect_to templates_path
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -13,6 +14,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::BuildsController &amp;lt; ApplicationController
 
   def create
     &amp;lt; at &amp;gt;tpl = Template.find(params[:template_id])
+    check_permission
     &amp;lt; at &amp;gt;all_targets = Image.available_targets
 
     if params[:targets].blank?
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -43,9 +45,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::BuildsController &amp;lt; ApplicationController
   end
 
   def edit
+    # FIXME: is &amp;lt; at &amp;gt;tpl defined here? do we need check_permission here?
   end
 
   def update
+    # FIXME: is &amp;lt; at &amp;gt;tpl defined here? do we need check_permission here?
   end
 
   private
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -65,6 +69,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::BuildsController &amp;lt; ApplicationController
   end
 
   def check_permission
-    require_privilege(Privilege::IMAGE_MODIFY)
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;tpl)
   end
 end
diff --git a/src/app/controllers/image_factory/templates_controller.rb b/src/app/controllers/image_factory/templates_controller.rb
index fbba625..a1b0fec 100644
--- a/src/app/controllers/image_factory/templates_controller.rb
+++ b/src/app/controllers/image_factory/templates_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,7 +2,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; require 'util/repository_manager'
 
 class ImageFactory::TemplatesController &amp;lt; ApplicationController
   before_filter :require_user
-  before_filter :check_permission, :except =&amp;gt; [:index, :show]
   before_filter :load_templates, :only =&amp;gt; [:index, :show]
 
   def index
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -10,6 +9,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
 
   def show
     &amp;lt; at &amp;gt;tpl = Template.find(params[:id])
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;tpl)
     &amp;lt; at &amp;gt;url_params = params.clone
     &amp;lt; at &amp;gt;tab_captions = ['Properties', 'Images']
     &amp;lt; at &amp;gt;details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab]
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -26,6 +26,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
   end
 
   def new
+    check_create_permission
     # can't use &amp;lt; at &amp;gt;template variable - is used by compass (or something other)
     &amp;lt; at &amp;gt;tpl = Template.new(params[:tpl])
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -34,9 +35,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
   def add_selected
     if params[:tpl] and not params[:tpl][:id].blank?
       &amp;lt; at &amp;gt;tpl = Template.find(params[:tpl][:id])
+      check_edit_permission
       &amp;lt; at &amp;gt;tpl.attributes = params[:tpl]
     else
       &amp;lt; at &amp;gt;tpl = Template.new(params[:tpl])
+      check_create_permission
     end
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
     &amp;lt; at &amp;gt;tpl.add_software(params[:packages].to_a + params[:selected_packages].to_a + params[:cached_packages].to_a,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -46,11 +49,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
 
   def edit
     &amp;lt; at &amp;gt;tpl = Template.find(params[:id])
+    check_edit_permission
     &amp;lt; at &amp;gt;tpl.attributes = params[:tpl] unless params[:tpl].blank?
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
   end
 
   def create
+    check_create_permission
     &amp;lt; at &amp;gt;tpl = Template.new(params[:tpl])
     &amp;lt; at &amp;gt;tpl.packages = params[:packages]
     if &amp;lt; at &amp;gt;tpl.save
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -65,6 +70,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
 
   def update
     &amp;lt; at &amp;gt;tpl = Template.find(params[:id])
+    check_edit_permission
     &amp;lt; at &amp;gt;tpl.packages = []
 
     if &amp;lt; at &amp;gt;tpl.update_attributes(params[:tpl])
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -120,7 +126,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
   end
 
   def managed_content
-    &amp;lt; at &amp;gt;tpl = params[:template_id].blank? ? Template.new : Template.find(params[:template_id])
+    if params[:template_id].blank?
+      &amp;lt; at &amp;gt;tpl = Template.new
+      check_create_permission
+    else
+      &amp;lt; at &amp;gt;tpl = Template.find(params[:template_id])
+      check_edit_permission
+    end
     &amp;lt; at &amp;gt;tpl.add_software(params[:packages].to_a + params[:selected_packages].to_a,
                       params[:groups].to_a + params[:selected_groups].to_a)
     render :layout =&amp;gt; false
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -133,9 +145,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
     else
       errs = {}
       Template.find(ids).each do |t|
-        t.destroy
-        unless t.destroyed?
-          errs[t.name] = t.errors.full_messages.join(". ")
+        if check_permission(Privilege::ACTION_MODIFY, t)
+          t.destroy
+          errs[t.name] = t.errors.full_messages.join(". ") unless t.destroyed?
+        else
+          errs[t.name] = "You don't have permission to delete #{t.name}"
         end
       end
       if errs.empty?
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -148,9 +162,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
   end
 
   def assembly
+    # FIXME: do we need perm check here?
   end
 
   def deployment_definition
+    # FIXME: do we need perm check here?
     &amp;lt; at &amp;gt;all_targets = Image.available_targets
   end
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -158,9 +174,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
     params[:packages].delete(params[:name]) unless params[:name].blank?
     if params[:tpl] and not params[:tpl][:id].blank?
       &amp;lt; at &amp;gt;tpl = Template.find(params[:tpl][:id])
+      check_edit_permission
       &amp;lt; at &amp;gt;tpl.attributes = params[:tpl]
     else
       &amp;lt; at &amp;gt;tpl = Template.new(params[:tpl])
+      check_create_permission
     end
     &amp;lt; at &amp;gt;tpl.add_software(params[:packages].to_a, params[:groups].to_a)
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -168,9 +186,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
   end
 
   def multi_destroy
-    # FIXME: set correct check permission when we will have it
-    require_privilege(Privilege::IMAGE_MODIFY)
-    Template.destroy(params[:selected])
+    &amp;lt; at &amp;gt;tpl = Template.find(params[:selected])
+    if check_edit_permission
+      &amp;lt; at &amp;gt;tpl.destroy
+      errs[&amp;lt; at &amp;gt;tpl.name] = &amp;lt; at &amp;gt;tpl.errors.full_messages.join(". ") unless &amp;lt; at &amp;gt;tpl.destroyed?
+    else
+      errs[&amp;lt; at &amp;gt;tpl.name] = "You don't have permission to delete #{&amp;lt; at &amp;gt;tpl.name}"
+    end
     redirect_to image_factory_templates_url
   end
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -184,7 +206,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
       {:name =&amp;gt; 'ARCH', :sort_attr =&amp;gt; 'templates.architecture'},
       {:name =&amp;gt; 'STATUS', :sort_attr =&amp;gt; 'status'},
     ]
-    require_privilege(Privilege::IMAGE_VIEW)
     &amp;lt; at &amp;gt;images = tpl.images
   end
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -197,18 +218,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
       {:name =&amp;gt; 'ARCH', :sort_attr =&amp;gt; 'architecture'},
     ]
 
-    # TODO: add template permission check
-    require_privilege(Privilege::IMAGE_VIEW)
-    &amp;lt; at &amp;gt;templates = Template.find(
-      :all,
-      :include =&amp;gt; :images,
-      :order =&amp;gt; get_order('name')
-    )
+    &amp;lt; at &amp;gt;templates = Template.list_for_user(Privilege::ACTION_VIEW,
+                                        :include =&amp;gt; :images,
+                                        :order =&amp;gt; get_order('name')
+                                        )
     &amp;lt; at &amp;gt;url_params = params.clone
   end
 
   def set_package_vars(set_all = false)
-    &amp;lt; at &amp;gt;tpl = params[:id].blank? ? Template.new : Template.find(params[:id])
+    if params[:id].blank?
+      &amp;lt; at &amp;gt;tpl = Template.new
+      check_create_permission
+    else
+      &amp;lt; at &amp;gt;tpl = Template.find(params[:id])
+      check_edit_permission
+    end
     &amp;lt; at &amp;gt;tpl.attributes = params[:tpl] unless params[:tpl].nil?
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
     &amp;lt; at &amp;gt;groups = &amp;lt; at &amp;gt;repository_manager.groups
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -230,8 +254,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ImageFactory::TemplatesController &amp;lt; ApplicationController
     flash.now[:error][:failures].merge!(errs)
   end
 
-  def check_permission
-    require_privilege(Privilege::IMAGE_MODIFY)
+  def check_create_permission
+    require_privilege(Privilege::ACTION_CREATE, Template)
+  end
+
+  def check_edit_permission
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;tpl)
   end
 
   def get_selected_id
diff --git a/src/app/controllers/instances_controller.rb b/src/app/controllers/instances_controller.rb
index 5e68b8e..142a336 100644
--- a/src/app/controllers/instances_controller.rb
+++ b/src/app/controllers/instances_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -35,7 +35,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class InstancesController &amp;lt; ApplicationController
   end
 
   def index
-    &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::INSTANCE_MODIFY)
+    &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_MODIFY, :target_type =&amp;gt; Instance)
 
     &amp;lt; at &amp;gt;order_dir = params[:order_dir] == 'desc' ? 'desc' : 'asc'
     &amp;lt; at &amp;gt;order_field = params[:order_field] || 'name'
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -69,7 +69,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class InstancesController &amp;lt; ApplicationController
 
   def new
     &amp;lt; at &amp;gt;instance = Instance.new(params[:instance])
-    require_privilege(Privilege::INSTANCE_MODIFY, &amp;lt; at &amp;gt;instance.pool) if &amp;lt; at &amp;gt;instance.pool
+    require_privilege(Privilege::ACTION_CREATE, Instance, &amp;lt; at &amp;gt;instance.pool) if &amp;lt; at &amp;gt;instance.pool
     # FIXME: we need to list only templates for particular user,
     # =&amp;gt; TODO: add TEMPLATE_* permissions
     &amp;lt; at &amp;gt;templates = Template.paginate(
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -81,7 +81,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class InstancesController &amp;lt; ApplicationController
 
   def configure
     &amp;lt; at &amp;gt;instance = Instance.new(params[:instance])
-    require_privilege(Privilege::INSTANCE_MODIFY, &amp;lt; at &amp;gt;instance.pool)
+    require_privilege(Privilege::ACTION_CREATE, Instance, &amp;lt; at &amp;gt;instance.pool)
     &amp;lt; at &amp;gt;hardware_profiles = HardwareProfile.find(:all, :include =&amp;gt; :architecture,
                                    :conditions =&amp;gt; {:provider_id =&amp;gt; nil,
                                    'hardware_profile_properties.value' =&amp;gt; &amp;lt; at &amp;gt;instance.template.architecture})
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -97,7 +97,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class InstancesController &amp;lt; ApplicationController
     &amp;lt; at &amp;gt;instance.state = Instance::STATE_NEW
     &amp;lt; at &amp;gt;instance.owner = current_user
 
-    require_privilege(Privilege::INSTANCE_MODIFY,
+    require_privilege(Privilege::ACTION_CREATE, Instance,
                       Pool.find(&amp;lt; at &amp;gt;instance.pool_id))
     #FIXME: This should probably be in a transaction
     if &amp;lt; at &amp;gt;instance.save!
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -131,7 +131,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class InstancesController &amp;lt; ApplicationController
     end
 
     &amp;lt; at &amp;gt;instance = Instance.find((params[:id] || []).first)
-    require_privilege(Privilege::INSTANCE_CONTROL,&amp;lt; at &amp;gt;instance.pool)
+    require_privilege(Privilege::ACTION_USE,&amp;lt; at &amp;gt;instance)
 
     if params[:instance_details]
       render :action =&amp;gt; 'show'
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -190,7 +190,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class InstancesController &amp;lt; ApplicationController
 
   def instance
     &amp;lt; at &amp;gt;instance = Instance.find(params[:id])
-    require_privilege(Privilege::INSTANCE_VIEW, &amp;lt; at &amp;gt;instance.pool)
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;instance)
   end
 
 end
diff --git a/src/app/controllers/permissions_controller.rb b/src/app/controllers/permissions_controller.rb
index c326e14..a2991d9 100644
--- a/src/app/controllers/permissions_controller.rb
+++ b/src/app/controllers/permissions_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -21,15 +21,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PermissionsController &amp;lt; ApplicationController
 
   def show
     &amp;lt; at &amp;gt;permission = Permission.find(params[:id])
-    require_privilege(Privilege::PERM_VIEW, &amp;lt; at &amp;gt;permission.permission_object)
+    require_privilege(Privilege::ACTION_PERM_VIEW, &amp;lt; at &amp;gt;permission.permission_object)
   end
 
   def list
-    set_permission_object Privilege::PERM_VIEW
+    set_permission_object Privilege::ACTION_PERM_VIEW
   end
 
   def new
-    set_permission_object Privilege::PERM_SET
+    set_permission_object Privilege::ACTION_PERM_SET
     &amp;lt; at &amp;gt;permission = Permission.new(:permission_object_type =&amp;gt; &amp;lt; at &amp;gt;permission_object.class,
                                  :permission_object_id =&amp;gt; &amp;lt; at &amp;gt;permission_object.id)
     &amp;lt; at &amp;gt;users = User.all
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -38,7 +38,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PermissionsController &amp;lt; ApplicationController
 
   def create
     &amp;lt; at &amp;gt;permission = Permission.new(params[:permission])
-    require_privilege(Privilege::PERM_SET, &amp;lt; at &amp;gt;permission.permission_object)
+    require_privilege(Privilege::ACTION_PERM_SET, &amp;lt; at &amp;gt;permission.permission_object)
     if request.post? &amp;amp;&amp;amp; &amp;lt; at &amp;gt;permission.save
       flash[:notice] = "Permission record added."
       redirect_to :action =&amp;gt; "list",
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -55,7 +55,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PermissionsController &amp;lt; ApplicationController
   def destroy
     if request.post?
       p =Permission.find(params[:permission][:id])
-      require_privilege(Privilege::PERM_SET, p.permission_object)
+      require_privilege(Privilege::ACTION_PERM_SET, p.permission_object)
       p.destroy
     end
     redirect_to :action =&amp;gt; "list",
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -65,7 +65,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PermissionsController &amp;lt; ApplicationController
 
   private
 
-  def set_permission_object(privilege)
+  def set_permission_object(action)
     if !params[:permission_object_type].nil?
       &amp;lt; at &amp;gt;permission_object = 
         params[:permission_object_type].constantize.find(params[:permission_object_id])
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -83,7 +83,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PermissionsController &amp;lt; ApplicationController
  
     raise ActiveRecord::RecordNotFound if &amp;lt; at &amp;gt;permission_object.nil?
 
-    require_privilege(privilege, &amp;lt; at &amp;gt;permission_object)
+    require_privilege(action, &amp;lt; at &amp;gt;permission_object)
   end
 
 end
diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb
index 47cdc77..fdc3650 100644
--- a/src/app/controllers/pools_controller.rb
+++ b/src/app/controllers/pools_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -44,16 +44,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PoolsController &amp;lt; ApplicationController
 
   def show
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;pool)
   end
 
   def edit
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;pool)
   end
 
   def list
     #FIXME: clean this up, many error cases here
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
-    require_privilege(Privilege::INSTANCE_VIEW,&amp;lt; at &amp;gt;pool)
+    # FIXME: really we need perm-filtered list here
+    require_privilege(Privilege::ACTION_VIEW, Instance, &amp;lt; at &amp;gt;pool)
     &amp;lt; at &amp;gt;pool.reload
 
     &amp;lt; at &amp;gt;order_dir = params[:order_dir] == 'desc' ? 'desc' : 'asc'
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -74,23 +77,23 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PoolsController &amp;lt; ApplicationController
   def hardware_profiles
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
     &amp;lt; at &amp;gt;hardware_profiles = &amp;lt; at &amp;gt;pool.hardware_profiles
-    require_privilege(Privilege::POOL_VIEW, &amp;lt; at &amp;gt;pool)
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;pool)
   end
 
   def realms
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
     &amp;lt; at &amp;gt;realm_names = &amp;lt; at &amp;gt;pool.realms
-    require_privilege(Privilege::POOL_VIEW,&amp;lt; at &amp;gt;pool)
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;pool)
   end
 
   def new
-    require_privilege(Privilege::POOL_MODIFY)
-    &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::POOL_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Pool)
+    &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_MODIFY)
     &amp;lt; at &amp;gt;pool = Pool.new
   end
 
   def create
-    require_privilege(Privilege::POOL_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Pool)
 
     #FIXME: This should probably be in a transaction
     &amp;lt; at &amp;gt;pool = Pool.new(params[:pool])
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -118,6 +121,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PoolsController &amp;lt; ApplicationController
       if type == "edit"
         redirect_to :action =&amp;gt; 'edit', :id =&amp;gt; pool_id
       elsif type == "delete"
+        require_privilege(Privilege::ACTION_MODIFY, Pool.find(pool_id))
         params[:id] = pool_id
         destroy
       end
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -130,27 +134,5 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PoolsController &amp;lt; ApplicationController
   def delete
   end
 
-  def accounts_for_pool
-    &amp;lt; at &amp;gt;pool =  Pool.find(params[:pool_id])
-    require_privilege(Privilege::ACCOUNT_VIEW,&amp;lt; at &amp;gt;pool)
-    &amp;lt; at &amp;gt;cloud_accounts = []
-    all_accounts = CloudAccount.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACCOUNT_ADD)
-    all_accounts.each {|account|
-      &amp;lt; at &amp;gt;cloud_accounts &amp;lt;&amp;lt; account unless &amp;lt; at &amp;gt;pool.cloud_accounts.map{|x| x.id}.include?(account.id)
-    }
-  end
-
-  def add_account
-    &amp;lt; at &amp;gt;pool = Pool.find(params[:pool])
-    &amp;lt; at &amp;gt;cloud_account = CloudAccount.find(params[:cloud_account])
-    require_privilege(Privilege::ACCOUNT_ADD,&amp;lt; at &amp;gt;pool)
-    require_privilege(Privilege::ACCOUNT_ADD,&amp;lt; at &amp;gt;cloud_account)
-    Pool.transaction do
-      &amp;lt; at &amp;gt;pool.cloud_accounts &amp;lt;&amp;lt; &amp;lt; at &amp;gt;cloud_account unless &amp;lt; at &amp;gt;pool.cloud_accounts.map{|x| x.id}.include?(&amp;lt; at &amp;gt;cloud_account.id)
-      &amp;lt; at &amp;gt;pool.save!
-      &amp;lt; at &amp;gt;pool.populate_realms([&amp;lt; at &amp;gt;cloud_account])
-    end
-    redirect_to :action =&amp;gt; 'show', :id =&amp;gt; &amp;lt; at &amp;gt;pool.id
-  end
   kick_condor
 end
diff --git a/src/app/controllers/providers_controller.rb b/src/app/controllers/providers_controller.rb
index 0754d65..0104f95 100644
--- a/src/app/controllers/providers_controller.rb
+++ b/src/app/controllers/providers_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -32,25 +32,25 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ProvidersController &amp;lt; ApplicationController
 
   def show
     &amp;lt; at &amp;gt;provider = Provider.find(:first, :conditions =&amp;gt; {:id =&amp;gt; params[:id]})
-    require_privilege(Privilege::PROVIDER_VIEW, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;provider)
   end
 
   def edit
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_MODIFY)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
     &amp;lt; at &amp;gt;provider = Provider.find(:first, :conditions =&amp;gt; {:id =&amp;gt; params[:id]})
-    require_privilege(Privilege::PROVIDER_MODIFY, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;provider)
   end
 
   def new
-    require_privilege(Privilege::PROVIDER_MODIFY)
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Provider)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_MODIFY)
     &amp;lt; at &amp;gt;provider = Provider.new(params[:provider])
     kick_condor
   end
 
   def create
-    require_privilege(Privilege::PROVIDER_MODIFY)
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Provider)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_MODIFY)
     &amp;lt; at &amp;gt;provider = Provider.new(params[:provider])
 
     if params[:test_connection]
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -70,9 +70,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ProvidersController &amp;lt; ApplicationController
   end
 
   def update
-    require_privilege(Privilege::PROVIDER_MODIFY)
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_MODIFY)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_MODIFY)
     &amp;lt; at &amp;gt;provider = Provider.find(:first, :conditions =&amp;gt; {:id =&amp;gt; params[:id]})
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;provider)
     previous_cloud_type = &amp;lt; at &amp;gt;provider.cloud_type
 
     &amp;lt; at &amp;gt;provider.update_attributes(params[:provider])
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -99,7 +99,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ProvidersController &amp;lt; ApplicationController
   def destroy
     if request.post? || request.delete?
       &amp;lt; at &amp;gt;provider = Provider.find(params[:id])
-      require_privilege(Privilege::PROVIDER_MODIFY, &amp;lt; at &amp;gt;provider)
+      require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;provider)
       if &amp;lt; at &amp;gt;provider.destroy and &amp;lt; at &amp;gt;provider.destroyed?
         redirect_to :action =&amp;gt; "index"
         flash[:notice] = "Provider Deleted"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -117,17 +117,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ProvidersController &amp;lt; ApplicationController
   def hardware_profiles
     &amp;lt; at &amp;gt;provider = Provider.find(params[:id])
     &amp;lt; at &amp;gt;hardware_profiles = &amp;lt; at &amp;gt;provider.hardware_profiles
-    require_privilege(Privilege::PROVIDER_VIEW, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;provider)
   end
 
   def realms
     &amp;lt; at &amp;gt;provider = Provider.find(params[:id])
     &amp;lt; at &amp;gt;realm_names = &amp;lt; at &amp;gt;provider.realms.collect { |r| r.name }
-    require_privilege(Privilege::PROVIDER_VIEW, &amp;lt; at &amp;gt;provider)
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;provider)
   end
 
   def settings
     &amp;lt; at &amp;gt;provider = Provider.find(params[:id])
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;provider)
   end
 
   def list
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -145,6 +146,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class ProvidersController &amp;lt; ApplicationController
 
   protected
   def load_providers
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_VIEW)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
   end
 end
diff --git a/src/app/controllers/quotas_controller.rb b/src/app/controllers/quotas_controller.rb
index e9937fb..df9bb41 100644
--- a/src/app/controllers/quotas_controller.rb
+++ b/src/app/controllers/quotas_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -28,7 +28,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class QuotasController &amp;lt; ApplicationController
     &amp;lt; at &amp;gt;parent_type = params[:parent_type]
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;parent.quota
 
-    require_privilege(Privilege::QUOTA_VIEW, &amp;lt; at &amp;gt;parent)
+    require_privilege(Privilege::ACTION_VIEW, Quota, &amp;lt; at &amp;gt;parent)
   end
 
   def edit
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -38,13 +38,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class QuotasController &amp;lt; ApplicationController
 
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;parent.quota
 
-    require_privilege(Privilege::QUOTA_MODIFY, &amp;lt; at &amp;gt;parent)
+    require_privilege(Privilege::ACTION_MODIFY, Quota, &amp;lt; at &amp;gt;parent)
   end
 
   def update
     &amp;lt; at &amp;gt;parent = &amp;lt; at &amp;gt;parent = get_parent_object(params)
     &amp;lt; at &amp;gt;parent_type = params[:parent_type]
-    require_privilege(Privilege::QUOTA_MODIFY, &amp;lt; at &amp;gt;parent)
+    require_privilege(Privilege::ACTION_MODIFY, Quota, &amp;lt; at &amp;gt;parent)
 
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;parent.quota
     &amp;lt; at &amp;gt;name = get_parent_name(&amp;lt; at &amp;gt;parent, &amp;lt; at &amp;gt;parent_type)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -60,7 +60,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class QuotasController &amp;lt; ApplicationController
   def reset
     &amp;lt; at &amp;gt;parent = &amp;lt; at &amp;gt;parent = get_parent_object(params)
     &amp;lt; at &amp;gt;parent_type = params[:parent_type]
-    require_privilege(Privilege::QUOTA_MODIFY, &amp;lt; at &amp;gt;parent)
+    require_privilege(Privilege::ACTION_MODIFY, Quota, &amp;lt; at &amp;gt;parent)
 
     &amp;lt; at &amp;gt;quota = &amp;lt; at &amp;gt;parent.quota
     &amp;lt; at &amp;gt;quota.maximum_running_instances = Quota::NO_LIMIT
diff --git a/src/app/controllers/resources/instances_controller.rb b/src/app/controllers/resources/instances_controller.rb
index 3bd0c45..241dbba 100644
--- a/src/app/controllers/resources/instances_controller.rb
+++ b/src/app/controllers/resources/instances_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -5,7 +5,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::InstancesController &amp;lt; ApplicationController
 
   def new
     &amp;lt; at &amp;gt;instance = Instance.new(params[:instance])
-    #require_privilege(Privilege::INSTANCE_MODIFY, &amp;lt; at &amp;gt;instance.pool) if &amp;lt; at &amp;gt;instance.pool
+    #require_privilege(Privilege::ACTION_CREATE, Instance, &amp;lt; at &amp;gt;instance.pool) if &amp;lt; at &amp;gt;instance.pool
 
     unless &amp;lt; at &amp;gt;instance.template
       redirect_to select_template_resources_instances_path
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -36,7 +36,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::InstancesController &amp;lt; ApplicationController
     &amp;lt; at &amp;gt;instance.owner = current_user
 
     begin
-      require_privilege(Privilege::INSTANCE_MODIFY,
+      require_privilege(Privilege::ACTION_CREATE, Instance,
                         Pool.find(&amp;lt; at &amp;gt;instance.pool_id))
       free_quota = Quota.can_start_instance?(&amp;lt; at &amp;gt;instance, nil)
       &amp;lt; at &amp;gt;instance.transaction do
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -120,11 +120,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::InstancesController &amp;lt; ApplicationController
 
   def load_instance
     &amp;lt; at &amp;gt;instance = Instance.find((params[:id] || []).first)
-    require_privilege(Privilege::INSTANCE_CONTROL,&amp;lt; at &amp;gt;instance.pool)
+    require_privilege(Privilege::ACTION_USE,&amp;lt; at &amp;gt;instance)
   end
 
   def init_new_instance_attrs
-    &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::INSTANCE_MODIFY)
+    &amp;lt; at &amp;gt;pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_MODIFY, :target_type =&amp;gt; Instance)
     &amp;lt; at &amp;gt;realms = Realm.find(:all, :conditions =&amp;gt; { :provider_id =&amp;gt; nil })
     &amp;lt; at &amp;gt;hardware_profiles = HardwareProfile.all(
       :include =&amp;gt; :architecture,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -145,7 +145,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::InstancesController &amp;lt; ApplicationController
       {:name =&amp;gt; 'CREATED BY', :sort_attr =&amp;gt; 'users.last_name'},
     ]
 
-    pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::INSTANCE_MODIFY)
+    pools = Pool.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_MODIFY, :target_type =&amp;gt; Instance)
     &amp;lt; at &amp;gt;instances = Instance.all(
       :include =&amp;gt; [:template, :owner],
       :conditions =&amp;gt; {:pool_id =&amp;gt; pools},
diff --git a/src/app/controllers/resources/pools_controller.rb b/src/app/controllers/resources/pools_controller.rb
index ffd1f55..3205da9 100644
--- a/src/app/controllers/resources/pools_controller.rb
+++ b/src/app/controllers/resources/pools_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -18,6 +18,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::PoolsController &amp;lt; ApplicationController
 
   def show
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
+    require_privilege(Privilege::ACTION_VIEW, &amp;lt; at &amp;gt;pool)
     &amp;lt; at &amp;gt;url_params = params.clone
     &amp;lt; at &amp;gt;tab_captions = ['Properties', 'Deployments', 'Instances', 'History', 'Permissions']
     &amp;lt; at &amp;gt;details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab]
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,12 +34,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::PoolsController &amp;lt; ApplicationController
   end
 
   def new
-    require_privilege(Privilege::POOL_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Pool)
     &amp;lt; at &amp;gt;pool = Pool.new
   end
 
   def create
-    require_privilege(Privilege::POOL_MODIFY)
+    require_privilege(Privilege::ACTION_CREATE, Pool)
 
     &amp;lt; at &amp;gt;pool = Pool.new(params[:pool])
     quota = Quota.new
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -55,15 +56,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::PoolsController &amp;lt; ApplicationController
   end
 
   def edit
-    require_privilege(Privilege::POOL_MODIFY)
-
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;pool)
   end
 
   def update
-    require_privilege(Privilege::POOL_MODIFY)
-
     &amp;lt; at &amp;gt;pool = Pool.find(params[:id])
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;pool)
     if &amp;lt; at &amp;gt;pool.update_attributes(params[:pool])
       flash[:notice] = "Pool updated."
       redirect_to :action =&amp;gt; 'show', :id =&amp;gt; &amp;lt; at &amp;gt;pool.id
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -73,7 +72,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Resources::PoolsController &amp;lt; ApplicationController
   end
 
   def multi_destroy
-    Pool.destroy(params[:pools_selected])
+    Pool.find(params[:pools_selected]).each do |pool|
+      pool.destroy if check_privilege(Privilege::ACTION_MODIFY, pool)
+    end
     redirect_to resources_pools_url
   end
 
diff --git a/src/app/controllers/settings_controller.rb b/src/app/controllers/settings_controller.rb
index ae20e12..0166e71 100644
--- a/src/app/controllers/settings_controller.rb
+++ b/src/app/controllers/settings_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -31,22 +31,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class SettingsController &amp;lt; ApplicationController
   end
 
   def index
-    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::PROVIDER_VIEW)
+    &amp;lt; at &amp;gt;providers = Provider.list_for_user(&amp;lt; at &amp;gt;current_user, Privilege::ACTION_VIEW)
   end
 
  def self_service
-   if !is_admin?
-     raise PermissionError.new('You have insufficient privileges to perform action.')
-     return
-   end
+   require_privilege(Privilege::ACTION_MODIFY)
    &amp;lt; at &amp;gt;self_service_default_quota = MetadataObject.lookup(SELF_SERVICE_DEFAULT_QUOTA)
  end
 
  def general_settings
-   if !is_admin?
-     raise PermissionError.new('You have insufficient privileges to perform action.')
-     return
-   end
+   require_privilege(Privilege::ACTION_MODIFY)
  end
 
  def update
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -76,9 +70,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class SettingsController &amp;lt; ApplicationController
    redirect_to :action =&amp;gt; 'self_service'
  end
 
- private
- def is_admin?
-   is_admin = &amp;lt; at &amp;gt;current_user.permissions.collect { |p| p.role }.find { |r| r.name == "Administrator" }
-   return is_admin == nil ? false : true
- end
 end
diff --git a/src/app/controllers/templates_controller.rb b/src/app/controllers/templates_controller.rb
index 403e6c3..e19c8e6 100644
--- a/src/app/controllers/templates_controller.rb
+++ b/src/app/controllers/templates_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,7 +2,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; require 'util/repository_manager'
 
 class TemplatesController &amp;lt; ApplicationController
   before_filter :require_user
-  before_filter :check_permission, :except =&amp;gt; :index
   layout :layout
 
   def layout
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -14,13 +13,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
   end
 
   def index
-    # TODO: add template permission check
-    require_privilege(Privilege::IMAGE_VIEW)
-    &amp;lt; at &amp;gt;templates = Template.find(
-      :all,
-      :include =&amp;gt; :images,
-      :order =&amp;gt; get_order('name')
-    )
+    &amp;lt; at &amp;gt;templates = Template.list_for_user(current_user,
+                                        Privilege::ACTION_VIEW,
+                                        :include =&amp;gt; :images,
+                                        :order =&amp;gt; get_order('name'))
   end
 
   def index_action
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -81,6 +77,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
   end
 
   def new
+    check_create_permission
     # can't use &amp;lt; at &amp;gt;template variable - is used by compass (or something other)
     &amp;lt; at &amp;gt;tpl = Template.new(params[:tpl])
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -91,12 +88,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
 
   def edit
     &amp;lt; at &amp;gt;tpl = Template.find(params[:id])
+    check_edit_permission
     &amp;lt; at &amp;gt;tpl.attributes = params[:tpl] unless params[:tpl].blank?
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
     render :action =&amp;gt; :edit
   end
 
   def create
+    check_create_permission
     &amp;lt; at &amp;gt;tpl = Template.new(params[:tpl])
     &amp;lt; at &amp;gt;tpl.packages = params[:packages]
     if &amp;lt; at &amp;gt;tpl.save
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -112,6 +111,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
   def update
     &amp;lt; at &amp;gt;tpl = Template.find(params[:id])
     &amp;lt; at &amp;gt;tpl.packages = []
+    check_edit_permission
 
     if &amp;lt; at &amp;gt;tpl.update_attributes(params[:tpl])
       &amp;lt; at &amp;gt;tpl.set_complete
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -163,7 +163,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
   end
 
   def managed_content
-    &amp;lt; at &amp;gt;tpl = params[:template_id].blank? ? Template.new : Template.find(params[:template_id])
+    if params[:template_id].blank?
+      &amp;lt; at &amp;gt;tpl = Template.new
+      check_create_permission
+    else
+      &amp;lt; at &amp;gt;tpl = Template.find(params[:template_id])
+      check_edit_permission
+    end
     &amp;lt; at &amp;gt;tpl.add_software(params[:packages].to_a + params[:selected_packages].to_a,
                       params[:groups].to_a + params[:selected_groups].to_a)
     render :layout =&amp;gt; false
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -176,9 +182,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
     else
       errs = {}
       Template.find(ids).each do |t|
-        t.destroy
-        unless t.destroyed?
-          errs[t.name] = t.errors.full_messages.join(". ")
+        if check_permission(Privilege::ACTION_MODIFY, t)
+          t.destroy
+          errs[t.name] = t.errors.full_messages.join(". ") unless t.destroyed?
+        else
+          errs[t.name] = "You don't have permission to delete #{t.name}"
         end
       end
       if errs.empty?
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -191,16 +199,24 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
   end
 
   def assembly
+    # FIXME: do we need perm check here?
   end
 
   def deployment_definition
+    # FIXME: do we need perm check here?
     &amp;lt; at &amp;gt;all_targets = Image.available_targets
   end
 
   private
 
   def set_package_vars(set_all = false)
-    &amp;lt; at &amp;gt;tpl = params[:id].blank? ? Template.new : Template.find(params[:id])
+    if params[:id].blank?
+      &amp;lt; at &amp;gt;tpl = Template.new
+      check_create_permission
+    else
+      &amp;lt; at &amp;gt;tpl = Template.find(params[:id])
+      check_edit_permission
+    end
     &amp;lt; at &amp;gt;tpl.attributes = params[:tpl] unless params[:tpl].nil?
     &amp;lt; at &amp;gt;repository_manager = RepositoryManager.new(:repositories =&amp;gt; params[:repository] || &amp;lt; at &amp;gt;tpl.platform)
     &amp;lt; at &amp;gt;groups = &amp;lt; at &amp;gt;repository_manager.groups
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -222,8 +238,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class TemplatesController &amp;lt; ApplicationController
     flash.now[:error][:failures].merge!(errs)
   end
 
-  def check_permission
-    require_privilege(Privilege::IMAGE_MODIFY)
+  def check_create_permission
+    require_privilege(Privilege::ACTION_CREATE, Template)
+  end
+
+  def check_edit_permission
+    require_privilege(Privilege::ACTION_MODIFY, &amp;lt; at &amp;gt;tpl)
   end
 
   def get_selected_id
diff --git a/src/app/controllers/users_controller.rb b/src/app/controllers/users_controller.rb
index 0e3220f..b462893 100644
--- a/src/app/controllers/users_controller.rb
+++ b/src/app/controllers/users_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -24,12 +24,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class UsersController &amp;lt; ApplicationController
   before_filter :current_user
 
   def new
+    require_privilege(Privilege::ACTION_CREATE, User) unless current_user.nil?
     &amp;lt; at &amp;gt;user = User.new
     &amp;lt; at &amp;gt;user.quota = Quota.new
   end
 
   def create
-    require_privilege(Privilege::USER_MODIFY) unless current_user.nil?
+    require_privilege(Privilege::ACTION_CREATE, User) unless current_user.nil?
     &amp;lt; at &amp;gt;user = User.new(params[:user])
 
     if params[:commit] == "Reset"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -58,39 +59,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class UsersController &amp;lt; ApplicationController
     else
       &amp;lt; at &amp;gt;user = current_user
     end
+    require_privilege(Privilege::ACTION_VIEW, User) unless current_user == &amp;lt; at &amp;gt;user
     &amp;lt; at &amp;gt;quota_resources = &amp;lt; at &amp;gt;user.quota.quota_resources()
   end
 
   def edit
-    &amp;lt; at &amp;gt;user = params[:id] ? User.find(params[:id]) : &amp;lt; at &amp;gt;current_user
-
-    if &amp;lt; at &amp;gt;user
-      if &amp;lt; at &amp;gt;user != &amp;lt; at &amp;gt;current_user
-        if !BasePermissionObject.general_permission_scope.can_modify_users(&amp;lt; at &amp;gt;current_user)
-          flash[:notice] = "Invalid Permission to perform this operation"
-          redirect_to users_path
-        end
-      end
-    end
+    &amp;lt; at &amp;gt;user = params[:id] ? User.find(params[:id]) : current_user
+    require_privilege(Privilege::ACTION_MODIFY, User) unless current_user == &amp;lt; at &amp;gt;user
   end
 
   def update
     &amp;lt; at &amp;gt;user = params[:user][:id] ? User.find(params[:user][:id]) : &amp;lt; at &amp;gt;current_user
+    require_privilege(Privilege::ACTION_MODIFY, User) unless current_user == &amp;lt; at &amp;gt;user
     if params[:commit] == "Save"
       if &amp;lt; at &amp;gt;user
-        has_users_modify = BasePermissionObject.general_permission_scope.can_modify_users(&amp;lt; at &amp;gt;current_user)
-        if &amp;lt; at &amp;gt;user != &amp;lt; at &amp;gt;current_user
-          if !has_users_modify
-            flash[:notice] = "Invalid Permission to perform this operation"
-            redirect_to :dashboard
-          end
-        end
         if &amp;lt; at &amp;gt;user.update_attributes(params[:user])
           flash[:notice] = "User updated!"
-          if has_users_modify
-            redirect_to users_path
-          else
+          if &amp;lt; at &amp;gt;user == current_user
             redirect_to :dashboard
+          else
+            redirect_to users_path
           end
         else
           render :action =&amp;gt; :edit
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -102,21 +90,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class UsersController &amp;lt; ApplicationController
   end
 
   def index
-    if &amp;lt; at &amp;gt;current_user.permissions.collect { |p| p.role }.find { |r| r.name == "Administrator" }
+    require_privilege(Privilege::ACTION_VIEW, User)
+    &amp;lt; at &amp;gt;users = User.all
+    sort_order = params[:sort_by].nil? ? "login" : params[:sort_by]
+    if sort_order == "percentage_quota_used"
       &amp;lt; at &amp;gt;users = User.all
-      sort_order = params[:sort_by].nil? ? "login" : params[:sort_by]
-      if sort_order == "percentage_quota_used"
-        &amp;lt; at &amp;gt;users = User.all
-        &amp;lt; at &amp;gt;users.sort! {|x,y| y.quota.percentage_used &amp;lt;=&amp;gt; x.quota.percentage_used }
-      elsif sort_order == "quota"
-        &amp;lt; at &amp;gt;users = User.all
-        &amp;lt; at &amp;gt;users.sort! {|x,y| (x.quota.maximum_running_instances and y.quota.maximum_running_instances) ? x.quota.maximum_running_instances &amp;lt;=&amp;gt; y.quota.maximum_running_instances : (x ? 1 : -1) }
-      else
-        &amp;lt; at &amp;gt;users = User.find(:all, :order =&amp;gt; sort_order)
-      end
+      &amp;lt; at &amp;gt;users.sort! {|x,y| y.quota.percentage_used &amp;lt;=&amp;gt; x.quota.percentage_used }
+    elsif sort_order == "quota"
+      &amp;lt; at &amp;gt;users = User.all
+      &amp;lt; at &amp;gt;users.sort! {|x,y| (x.quota.maximum_running_instances and y.quota.maximum_running_instances) ? x.quota.maximum_running_instances &amp;lt;=&amp;gt; y.quota.maximum_running_instances : (x ? 1 : -1) }
     else
-      flash[:notice] = "Invalid Permission to perform this operation"
-      redirect_to :dashboard
+      &amp;lt; at &amp;gt;users = User.find(:all, :order =&amp;gt; sort_order)
     end
   end
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -138,22 +122,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class UsersController &amp;lt; ApplicationController
   end
 
   def destroy
-    if &amp;lt; at &amp;gt;current_user.permissions.collect { |p| p.role }.find { |r| r.name == "Administrator" }
-      if request.post? || request.delete?
-        &amp;lt; at &amp;gt;user = User.find(params[:id])
-        if &amp;lt; at &amp;gt;user == &amp;lt; at &amp;gt;current_user
-          flash[:notice] = "Can not delete the currently logged in user!"
-        elsif &amp;lt; at &amp;gt;user.destroy
-          flash[:notice] = "User Deleted"
-        else
-          flash[:error] = {
-            :summary =&amp;gt; "Failed to delete User",
-            :failures =&amp;gt; &amp;lt; at &amp;gt;user.errors.full_messages,
-          }
-        end
+    require_privilege(Privilege::ACTION_MODIFY, User)
+    if request.post? || request.delete?
+      &amp;lt; at &amp;gt;user = User.find(params[:id])
+      if &amp;lt; at &amp;gt;user == &amp;lt; at &amp;gt;current_user
+        flash[:notice] = "Can not delete the currently logged in user!"
+      elsif &amp;lt; at &amp;gt;user.destroy
+        flash[:notice] = "User Deleted"
+      else
+        flash[:error] = {
+          :summary =&amp;gt; "Failed to delete User",
+          :failures =&amp;gt; &amp;lt; at &amp;gt;user.errors.full_messages,
+        }
       end
-    else
-      flash[:notice] = "Invalid Permission to perform this operation"
     end
     redirect_to users_path
   end
diff --git a/src/app/models/cloud_account.rb b/src/app/models/cloud_account.rb
index e4fe6c6..ee07b8d 100644
--- a/src/app/models/cloud_account.rb
+++ b/src/app/models/cloud_account.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -66,6 +66,27 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CloudAccount &amp;lt; ActiveRecord::Base
   before_destroy :destroyable?
   before_validation :read_x509_files
 
+  def object_list
+    super &amp;lt;&amp;lt; provider
+  end
+  class &amp;lt;&amp;lt; self
+    alias orig_list_for_user_include list_for_user_include
+    alias orig_list_for_user_conditions list_for_user_conditions
+  end
+
+  def self.list_for_user_include
+    includes = orig_list_for_user_include
+    includes &amp;lt;&amp;lt; { :provider =&amp;gt; {:permissions =&amp;gt; {:role =&amp;gt; :privileges}}}
+    includes
+  end
+
+  def self.list_for_user_conditions
+    "(#{orig_list_for_user_conditions}) or
+     (permissions_providers.user_id=:user and
+      privileges_roles.target_type=:target_type and
+      privileges_roles.action=:action)"
+  end
+
   def destroyable?
     instances.empty?
   end
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index 8573c5a..5aa500d 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -36,6 +36,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Instance &amp;lt; ActiveRecord::Base
   belongs_to :instance_key
   belongs_to :instance_hwp
 
+  has_many :permissions, :as =&amp;gt; :permission_object, :dependent =&amp;gt; :destroy,
+           :include =&amp;gt; [:role],
+           :order =&amp;gt; "permissions.id ASC"
+
   validates_presence_of :pool_id
   validates_presence_of :hardware_profile_id
   validates_presence_of :template_id
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -66,6 +70,27 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Instance &amp;lt; ActiveRecord::Base
   validates_inclusion_of :state,
      :in =&amp;gt; STATES
 
+  def object_list
+    super &amp;lt;&amp;lt; pool
+  end
+  class &amp;lt;&amp;lt; self
+    alias orig_list_for_user_include list_for_user_include
+    alias orig_list_for_user_conditions list_for_user_conditions
+  end
+
+  def self.list_for_user_include
+    includes = orig_list_for_user_include
+    includes &amp;lt;&amp;lt; { :pool =&amp;gt; {:permissions =&amp;gt; {:role =&amp;gt; :privileges}}}
+    includes
+  end
+
+  def self.list_for_user_conditions
+    "(#{orig_list_for_user_conditions}) or
+     (permissions_pools.user_id=:user and
+      privileges_roles.target_type=:target_type and
+      privileges_roles.action=:action)"
+  end
+
   def get_action_list(user=nil)
     # return empty list rather than nil
     # FIXME: not handling pending state now -- only current state
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -142,7 +167,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Instance &amp;lt; ActiveRecord::Base
     }
 
     instances = []
-    pools = Pool.list_for_user(user, Privilege::INSTANCE_VIEW)
+    pools = Pool.list_for_user(user, Privilege::ACTION_VIEW, Instance)
     pools.each{|pool| pool.instances.each {|i| instances &amp;lt;&amp;lt; i}}
     instances.each do |i|
       if i.state == Instance::STATE_RUNNING
diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb
index 349b6a7..22b228a 100644
--- a/src/app/models/permission.rb
+++ b/src/app/models/permission.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -29,12 +29,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Permission &amp;lt; ActiveRecord::Base
 
   belongs_to :permission_object,      :polymorphic =&amp;gt; true
   # type-specific associations
+  belongs_to :pool_family,            :class_name =&amp;gt; "PoolFamily",
+                                      :foreign_key =&amp;gt; "permission_object_id"
   belongs_to :pool,                   :class_name =&amp;gt; "Pool",
                                       :foreign_key =&amp;gt; "permission_object_id"
+  belongs_to :instance,               :class_name =&amp;gt; "Instance",
+                                      :foreign_key =&amp;gt; "permission_object_id"
   belongs_to :provider,               :class_name =&amp;gt; "Provider",
                                       :foreign_key =&amp;gt; "permission_object_id"
   belongs_to :cloud_account,          :class_name =&amp;gt; "CloudAccount",
                                       :foreign_key =&amp;gt; "permission_object_id"
+  belongs_to :template,               :class_name =&amp;gt; "Template",
+                                      :foreign_key =&amp;gt; "permission_object_id"
   belongs_to :base_permission_object, :class_name =&amp;gt; "BasePermissionObject",
                                       :foreign_key =&amp;gt; "permission_object_id"
 
diff --git a/src/app/models/permissioned_object.rb b/src/app/models/permissioned_object.rb
index 24aebe0..34efec8 100644
--- a/src/app/models/permissioned_object.rb
+++ b/src/app/models/permissioned_object.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -17,91 +17,77 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
 module PermissionedObject
-  def can_view_perms(user)
-    has_privilege(user, Privilege::PERM_VIEW)
-  end
-  def can_set_perms(user)
-    has_privilege(user, Privilege::PERM_SET)
-  end
-
-  def can_view_instances(user)
-    has_privilege(user, Privilege::INSTANCE_VIEW)
-  end
-  def can_modify_instances(user)
-    has_privilege(user, Privilege::INSTANCE_MODIFY)
-  end
-  def can_control_instances(user)
-    has_privilege(user, Privilege::INSTANCE_CONTROL)
-  end
-
-  def can_view_stats(user)
-    has_privilege(user, Privilege::STATS_VIEW)
-  end
-
-  def can_view_accounts(user)
-    has_privilege(user, Privilege::ACCOUNT_VIEW)
-  end
-  def can_modify_accounts(user)
-    has_privilege(user, Privilege::ACCOUNT_MODIFY)
-  end
-
-  def can_view_pools(user)
-    has_privilege(user, Privilege::POOL_VIEW)
-  end
-  def can_modify_pools(user)
-    has_privilege(user, Privilege::POOL_MODIFY)
-  end
 
-  def can_view_quotas(user)
-    has_privilege(user, Privilege::QUOTA_VIEW)
-  end
-  def can_modify_quotas(user)
-    has_privilege(user, Privilege::QUOTA_MODIFY)
-  end
-
-  def can_view_providers(user)
-    has_privilege(user, Privilege::PROVIDER_VIEW)
-  end
-  def can_modify_providers(user)
-    has_privilege(user, Privilege::PROVIDER_MODIFY)
-  end
-
-  def can_view_users(user)
-    has_privilege(user, Privilege::USER_VIEW)
-  end
-  def can_modify_users(user)
-    has_privilege(user, Privilege::USER_MODIFY)
-  end
-
-  def can_view_images(user)
-    has_privilege(user, Privilege::IMAGE_VIEW)
-  end
-  def can_modify_images(user)
-    has_privilege(user, Privilege::IMAGE_MODIFY)
+  def has_privilege(user, action, target_type=nil)
+    return false if user.nil? or action.nil?
+    target_type = self.class.default_privilege_target_type if target_type.nil?
+    object_list.each do |obj|
+      return true if obj.permissions.find(:first,
+                                          :include =&amp;gt; [:role =&amp;gt; :privileges],
+                                          :conditions =&amp;gt;
+                                          ["permissions.user_id=:user and
+                                            privileges.target_type=:target_type and
+                                            privileges.action=:action",
+                                           { :user =&amp;gt; user.id,
+                                             :target_type =&amp;gt; target_type.name,
+                                             :action =&amp;gt; action}])
+    end
+    return false
   end
 
-  def has_privilege(user, privilege)
-    return false if user.nil?
-    permissions.find(:first, :include =&amp;gt; [:role =&amp;gt; :privileges],
-                     :conditions =&amp;gt; ["permissions.user_id=:user and
-                                      privileges.name=:priv",
-                                     { :user =&amp;gt; user.id,
-                                       :priv =&amp;gt; privilege }])
+  # Returns the list of objects to check for permissions on -- by default
+  # this object plus the Base permission object
+  def object_list
+    [self, BasePermissionObject.general_permission_scope]
   end
 
   # Any methods here will be able to use the context of the
   # ActiveRecord model the module is included in.
   def self.included(base)
     base.class_eval do
-      def self.list_for_user(user, privilege)
-        if BasePermissionObject.general_permission_scope.has_privilege(user, privilege)
-          all
+      def self.default_privilege_target_type
+        self.name.constantize
+      end
+      def self.list_for_user_include
+        [{:permissions =&amp;gt; {:role =&amp;gt; :privileges}}]
+      end
+      def self.list_for_user_conditions
+        "permissions.user_id=:user and
+         privileges.target_type=:target_type and
+         privileges.action=:action"
+      end
+      # :conditions in hash must match form ["foo=:param and ...", {:param =&amp;gt; value}]
+      def self.list_for_user(user, action, find_hash={})
+        target_type = find_hash.fetch(:target_type, self.default_privilege_target_type)
+        query_include = find_hash[:include]
+        query_order = find_hash[:order]
+        query_conditions = find_hash[:conditions]
+        return [] if user.nil? or action.nil? or target_type.nil?
+        if BasePermissionObject.general_permission_scope.has_privilege(user,
+                                                                       action,
+                                                                       target_type)
+          find(:all, :include =&amp;gt; query_include,
+                     :order =&amp;gt; query_order,
+                     :conditions =&amp;gt; query_conditions)
         else
-          find(:all, :include =&amp;gt; {:permissions =&amp;gt; {:role =&amp;gt; :privileges}},
-               :conditions =&amp;gt; ["permissions.user_id=:user and
-                                privileges.name=:priv",
-                               {:user =&amp;gt; user.id,
-                                :priv =&amp;gt; privilege }])
+          include_clause = self.list_for_user_include
+          if query_include.is_a?(Array)
+            include_clause += query_include
+          elsif !query_include.nil?
+            include_clause &amp;lt;&amp;lt; query_include
+          end
+          conditions_hash = {:user =&amp;gt; user.id,
+                             :target_type =&amp;gt; target_type.name,
+                             :action =&amp;gt; action}
+          if query_conditions.nil?
+            conditions_str = self.list_for_user_conditions
+          else
+            conditions_str = "(#{self.list_for_user_include}) and (#{query_conditions[0]})"
+            conditions_hash.merge!(query_conditions[1]) { |key, h1, h2| h1 }
+          end
+          find(:all, :include =&amp;gt; include_clause,
+               :conditions =&amp;gt; [conditions_str, conditions_hash],
+               :order =&amp;gt; query_order)
         end
       end
     end
diff --git a/src/app/models/privilege.rb b/src/app/models/privilege.rb
index 552beef..6456d66 100644
--- a/src/app/models/privilege.rb
+++ b/src/app/models/privilege.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -18,66 +18,122 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # also available at http://www.gnu.org/copyleft/gpl.html.
 
 class Privilege &amp;lt; ActiveRecord::Base
-  has_and_belongs_to_many :roles
 
-  validates_presence_of :name
-  validates_uniqueness_of :name
+  ACTION_PERM_SET  = "set_perms"    # can create/modify/delete permission
+                                    # records on this object
+  ACTION_PERM_VIEW = "view_perms"   # can view permission records on this
+                                    # object
+  ACTION_CREATE    = "create"       # can create objects of this type here
+  ACTION_MODIFY    = "modify"       # can modify objects of this type here
+  ACTION_VIEW      = "view"         # can view objects of this type here
+  ACTION_USE       = "use"          # can use objects of this type here
+                                    # the meaning of 'use' is type-specific:
+                                    #   Template: add this template to an assembly
+                                    #   Assembly: add this assembly to a deployable
+                                    #   Deployable: choose this deployable to launch
+                                    #   Instance: may perform actions on this instance
+                                    #   Realm: may map this realm
+                                    #   CloudAccount: May add this account to PoolFamily
 
-  #default privileges
-  PERM_SET          = "set_perms"         # can create/modify/delete permission
-                                          # records on this object
-  PERM_VIEW         = "view_perms"        # can view permission records on this
-                                          # object
 
-  # instance privileges normally checked at the pool level, although
-  # instance-specific overrides could be a future enhancement.
-  INSTANCE_MODIFY   = "instance_modify"   # can create, modify, delete, or
-                                          # control (start, stop, etc) instances
-  INSTANCE_CONTROL  = "instance_control"  # can control (start, stop, etc)
-                                          # instances
-  INSTANCE_VIEW     = "instance_view"     # can view instance metadata
-  # do we need a separate "connect" privilege?
+  ACTIONS = [ ACTION_CREATE, ACTION_MODIFY, ACTION_USE, ACTION_VIEW,
+              ACTION_PERM_SET, ACTION_PERM_VIEW]
+  TYPES   = { BasePermissionObject =&amp;gt; [ACTION_MODIFY, ACTION_PERM_SET, ACTION_PERM_VIEW],
+              Template =&amp;gt; ACTIONS,
+              Pool =&amp;gt; ACTIONS - [ACTION_USE],
+              PoolFamily =&amp;gt; ACTIONS - [ACTION_USE],
+              Instance =&amp;gt; ACTIONS,
+              Quota =&amp;gt; [ACTION_VIEW, ACTION_MODIFY],
+              HardwareProfile =&amp;gt; ACTIONS - [ACTION_USE, ACTION_VIEW],
+              Realm =&amp;gt; ACTIONS - [ACTION_VIEW],
+              Provider =&amp;gt; ACTIONS - [ACTION_USE],
+              CloudAccount =&amp;gt; ACTIONS,
+              User =&amp;gt; [ ACTION_CREATE, ACTION_MODIFY, ACTION_VIEW] }
 
-  # stats privileges normally checked at the pool level, although
-  # instance-specific overrides could be a future enhancement.
-  STATS_VIEW        = "stats_view"        # can view monitoring data for
-                                          # instances
+  belongs_to :role
+  validates_presence_of :role_id
+  validates_presence_of :target_type
+  validates_presence_of :action
+  validates_uniqueness_of :action, :scope =&amp;gt; [:target_type, :role_id]
 
-  # to create(i.e. import) an account on a provider needs ACCOUNT_MODIFY on the
-  # provider.
-  ACCOUNT_MODIFY    = "account_modify"    # can create or modify cloud accounts
-  ACCOUNT_VIEW      = "account_view"      # can view cloud accounts
+  # notes on available privilege action/type pairs. Format is:
+  # Type          Scope
+  #   Action      Notes (action defined on scope above unless specified)
+  #
+  # BasePermissionObject   the base perm object
+  #   modify      Can modify system settings, etc.
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # Template  This template/assembly/deployable or all T/A/D in this TADCollection
+  #   view        Can view
+  #   use         Can assign T/A/D to TAD collection;
+  #                (if template) can add to assembly or can use to launch instance
+  #                (if assembly) can add to deployable
+  #                (if deployable) can use to launch deployment
+  #                (if TAD Collection) not used
+  #   modify      Can modify
+  #   create      Can create (on BasePermissionObject)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # Pool This pool
+  #   view        Can view
+  #   modify      Can modify
+  #   create      Can create (on BasePermissionObject)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # PoolFamily This PoolFamily
+  #   view        Can view
+  #   modify      Can modify
+  #   create      Can create (on BasePermissionObject)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # Instance This Instance or instances within this Pool
+  #   view        Can view
+  #   use         Can perform lifecycle actions on and/or view console
+  #   modify      Can modify
+  #   create      Can create (within this Pool)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions (or can set instance permissions on this pool)
+  #
+  # Quota  The Pool/CloudAccount/PoolFamily/User assigned the quota
+  #   view        Can view quota on this obj
+  #   modify      Can edit quota on this obj
+  #
+  # HardwareProfile This HardwareProfile
+  #   modify      (for Aeolus HWPs) Can modify
+  #   create      Can create (on BasePermissionObject)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # Realm This Realm (or realms within this provider)
+  #   use         (for provider Realm) can map realm or provider to aeolus realm
+  #   modify      (for Aeolus realms) Can modify
+  #   create      Can create (within this Pool)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # Provider This Provider
+  #   view        Can view
+  #   modify      Can modify
+  #   create      Can create (on BasePermissionObject)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # CloudAccount This CloudAccount
+  #   view        Can view
+  #   use         Can map to PoolFamily
+  #   modify      Can modify
+  #   create      Can create (within this Provider)
+  #   view_perms  Can view permissions
+  #   set_perms   Can set permissions
+  #
+  # User This User (set on BasePermissionObject)
+  #   view        Can view
+  #   modify      Can modify
+  #   create      Can create
 
-  POOL_MODIFY       = "pool_modify"       # can create or modify a pool
-  POOL_VIEW         = "pool_view"         # can view a pool
-
-  # quota privileges normally checked at the pool or account level,
-  # depending on which quota level we're dealing with
-  QUOTA_MODIFY      = "quota_modify"      # can create or modify a quota
-  QUOTA_VIEW        = "quota_view"        # can view a quota
-
-  # provider privileges normally checked at the provider level, although
-  # 'new provider' action requires this privilege at the SystemPermission level
-  PROVIDER_MODIFY   = "provider_modify"   # can create or modify a provider
-  PROVIDER_VIEW     = "provider_view"     # can view a provider
-
-  # normally checked at the SystemPermission level
-  USER_MODIFY       = "user_modify"       # can create a new user (other than
-                                          # self-registration) or modify another
-                                          # user's metadata (for admin-level
-                                          # actions)
-  USER_VIEW         = "user_view"         # can view a user's profile data
-
-  IMAGE_VIEW        = "image_view"        # can view existing images (templates)
-  IMAGE_MODIFY      = "image_modify"      # can create or modify images (templates)
-
-  FULL_PRIVILEGE_LIST = [PERM_SET, PERM_VIEW,
-                         INSTANCE_MODIFY, INSTANCE_CONTROL, INSTANCE_VIEW,
-                         STATS_VIEW,
-                         ACCOUNT_MODIFY, ACCOUNT_VIEW,
-                         POOL_MODIFY, POOL_VIEW,
-                         QUOTA_MODIFY, QUOTA_VIEW,
-                         PROVIDER_MODIFY, PROVIDER_VIEW,
-                         USER_MODIFY, USER_VIEW,
-                         IMAGE_VIEW, IMAGE_MODIFY]
 end
diff --git a/src/app/models/role.rb b/src/app/models/role.rb
index db4a9ac..300dad8 100644
--- a/src/app/models/role.rb
+++ b/src/app/models/role.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -18,10 +18,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # also available at http://www.gnu.org/copyleft/gpl.html.
 
 class Role &amp;lt; ActiveRecord::Base
-  has_many :permissions
-  has_and_belongs_to_many :privileges, :uniq =&amp;gt; true
+  has_many :permissions, :dependent =&amp;gt; :destroy
+  has_many :privileges, :dependent =&amp;gt; :destroy
 
+  validates_presence_of :scope
   validates_presence_of :name
   validates_uniqueness_of :name
 
+  validates_associated :privileges
+
 end
diff --git a/src/app/models/template.rb b/src/app/models/template.rb
index d545f9b..bff586d 100644
--- a/src/app/models/template.rb
+++ b/src/app/models/template.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,12 +2,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; require 'util/image_descriptor_xml'
 require 'typhoeus'
 
 class Template &amp;lt; ActiveRecord::Base
+  include PermissionedObject
   has_many :images, :dependent =&amp;gt; :destroy
   has_many :instances
   before_validation :generate_uuid
   before_save :update_xml
   before_destroy :no_instances?
 
+  has_many :permissions, :as =&amp;gt; :permission_object, :dependent =&amp;gt; :destroy,
+           :include =&amp;gt; [:role],
+           :order =&amp;gt; "permissions.id ASC"
+
   WAREHOUSE_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/image_warehouse.yml")
 
   validates_presence_of :uuid
diff --git a/src/app/services/application_service.rb b/src/app/services/application_service.rb
index 8161718..079c200 100644
--- a/src/app/services/application_service.rb
+++ b/src/app/services/application_service.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -40,19 +40,34 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; module ApplicationService
 
   # &amp;lt; at &amp;gt;current_user must be defined
 
-  def check_privilege(privilege, perm_obj)
-    ((perm_obj and perm_obj.has_privilege(current_user, privilege)) or
-     BasePermissionObject.general_permission_scope.has_privilege(current_user,
-                                                                 privilege))
+  def check_privilege(action, *type_and_perm_obj)
+    target_type = nil
+    perm_obj = nil
+    type_and_perm_obj.each do |obj|
+      target_type=obj if obj.class==Class
+      perm_obj=obj if obj.is_a?(ActiveRecord::Base)
+    end
+    perm_obj=&amp;lt; at &amp;gt;perm_obj if perm_obj.nil?
+    perm_obj=BasePermissionObject.general_permission_scope if perm_obj.nil?
+    perm_obj.has_privilege(current_user, action, target_type)
   end
 
-  def authorized?(privilege, perm_obj=nil)
+  # Require a given privilege level to view this page
+  #   1. action is always required -- what action is being done (from Privilege::ACTIONS)
+  #   2. perm_obj is optional -- This is the resource on which to look for permission
+  #         records. If omitted, check for site-wide permissions on BasePermissionObject
+  #   3. type is also optional -- if omitted it's taken from perm_obj.
+  #        For example, if action is 'view', perm_obj is a Pool and type is omitted,
+  #        then check for current user's "view pool" permission on this pool.
+  #        if action is 'view', perm_obj is a Pool and type is Quota,
+  #        then check for current user's "view quota" permission on this pool.
+  def require_privilege(action, *type_and_perm_obj)
+    perm_obj = nil
+    type_and_perm_obj.each do |obj|
+      perm_obj=obj if obj.is_a?(ActiveRecord::Base)
+    end
     &amp;lt; at &amp;gt;perm_obj = perm_obj
-    check_privilege(privilege,&amp;lt; at &amp;gt;perm_obj)
-  end
-
-  def require_privilege(privilege, perm_obj=nil)
-    unless authorized?(privilege, perm_obj)
+    unless check_privilege(action, *type_and_perm_obj)
       raise PermissionError.new(
                'You have insufficient privileges to perform action.')
     end
diff --git a/src/app/views/admin/users/_form.haml b/src/app/views/admin/users/_form.haml
index 3fdf33f..2d0945e 100644
--- a/src/app/views/admin/users/_form.haml
+++ b/src/app/views/admin/users/_form.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -8,7 +8,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 %fieldset
   = form.label :password_confirmation, t(:confirm_password), :class =&amp;gt; "grid_3 alpha"
   = form.password_field :password_confirmation, :class =&amp;gt; "grid_5"
--if has_user_modify?
+-if check_privilege(Privilege::ACTION_MODIFY, User)
   %fieldset.clear
     = form.label :user_status, "User Status:", :class =&amp;gt; "alpha grid_3"
     .grid_5
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -25,7 +25,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 %fieldset.clear
   = form.label :email, t(:email), :class =&amp;gt; "alpha grid_3"
   = form.text_field :email, :class =&amp;gt; "grid_5"
--if has_user_modify?
+-if check_privilege(Privilege::ACTION_MODIFY, User)
   %h3.grid_16 User Treatment
   %fieldset.clearfix
     = label_tag 'apply_treatment', t(:apply_treatment), :class =&amp;gt; "alpha grid_3"
diff --git a/src/app/views/admin/users/edit.haml b/src/app/views/admin/users/edit.haml
index a367fec..69319e9 100644
--- a/src/app/views/admin/users/edit.haml
+++ b/src/app/views/admin/users/edit.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,4 +1,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
&lt;/pre&gt;</description>
    <dc:creator>Scott Seago</dc:creator>
    <dc:date>2011-01-19T06:14:34</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3706">
    <title>InstanceKey patch (rev. 3)</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3706</link>
    <description>&lt;pre&gt;Fixed one spec test, which for some reason passes for me but not for Tomas.
&lt;/pre&gt;</description>
    <dc:creator>jprovazn-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-13T14:34:15</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3702">
    <title>[PATCH aeolus 1/2] Added Cucumber Tests forProvider Search</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3702</link>
    <description>&lt;pre&gt;From: Martyn Taylor &amp;lt;mtaylor-H+wXaHxf7aLQT0dZR+AlfA&amp;lt; at &amp;gt;public.gmane.org&amp;gt;

---
 src/features/provider.feature                   |   22 ++++++++++++++++++++++
 src/features/step_definitions/provider_steps.rb |    2 +-
 2 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/src/features/provider.feature b/src/features/provider.feature
index 9e6f398..08704dd 100644
--- a/src/features/provider.feature
+++ b/src/features/provider.feature
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -73,3 +73,25 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; Feature: Manage Providers
     And there should not be any hardware profiles
     And there should not be a cloud account
     And there should not be a realm
+
+  Scenario: Search for hardware profiles
+    Given there are these providers:
+    | name          | url                         |
+    | Test          | http://testprovider.com/api |
+    | Mock          | http://mockprovider.com/api |
+    | Other         | http://sometesturl.com/api  |
+    And I am on the admin providers page
+    Then I should see the following:
+    | Test  | http://testprovider.com/api |
+    | Mock  | http://mockprovider.com/ap  |
+    | Other | http://sometesturl.com/api  |
+    When I fill in "q" with "test"
+    And I press "Search"
+    Then I should see "Test"
+    And I should see "Other"
+    And I should not see "Mock"
+    When I fill in "q" with "Mock"
+    And I press "Search"
+    Then I should see "Mock"
+    And I should not see "Test"
+    And I should not see "Other"
\ No newline at end of file
diff --git a/src/features/step_definitions/provider_steps.rb b/src/features/step_definitions/provider_steps.rb
index 2673ae8..bc56276 100644
--- a/src/features/step_definitions/provider_steps.rb
+++ b/src/features/step_definitions/provider_steps.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -32,7 +32,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; end
 
 Given /^there are these providers:$/ do |table|
   table.hashes.each do |hash|
-    Factory(:mock_provider, :name =&amp;gt; hash['name'])
+    hash['url'].nil? ? Factory(:mock_provider, :name =&amp;gt; hash['name']) : Factory(:mock_provider, :name =&amp;gt; hash['name'], :url =&amp;gt; hash['url'])
   end
 end
 
&lt;/pre&gt;</description>
    <dc:creator>mtaylor-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-17T17:34:25</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3698">
    <title>[PATCH aeolus] admin,Hardware Profiles UI for new Hardware Profile Model</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3698</link>
    <description>&lt;pre&gt;From: Martyn Taylor &amp;lt;mtaylor-H+wXaHxf7aLQT0dZR+AlfA&amp;lt; at &amp;gt;public.gmane.org&amp;gt;

This patch allows users to create Hardware Profiles based on the new matching model.

N.B. Building the Hardware Profile in the HardwareProfile controller, is not very RESTy.  This was a decision made to simplify the UI slightly, and create HardareProfile with breaking any validation.
---
 .../admin/hardware_profiles_controller.rb          |  135 +++++++++++++++++++-
 src/app/models/hardware_profile.rb                 |   13 ++-
 src/app/models/hardware_profile_property.rb        |    2 +-
 src/app/models/property_enum_entry.rb              |    3 +
 src/app/stylesheets/newui.scss                     |    5 +
 src/app/views/admin/hardware_profiles/_form.haml   |   28 ++++
 src/app/views/admin/hardware_profiles/_list.haml   |   35 +++---
 .../_matching_provider_hardware_profiles.haml      |    8 +-
 .../views/admin/hardware_profiles/_properties.haml |    1 +
 src/app/views/admin/hardware_profiles/create.haml  |    6 +
 src/app/views/admin/hardware_profiles/edit.haml    |    7 +
 src/app/views/admin/hardware_profiles/new.haml     |    7 +
 src/app/views/admin/provider_accounts/new.haml     |    2 +-
 src/config/routes.rb                               |    2 +
 .../20090804135630_create_hardware_profiles.rb     |    2 +-
 src/features/hardware_profile.feature              |   60 +++++++++
 .../step_definitions/hardware_profile_steps.rb     |   17 +++
 src/features/support/paths.rb                      |    6 +
 18 files changed, 310 insertions(+), 29 deletions(-)
 create mode 100644 src/app/views/admin/hardware_profiles/_form.haml
 create mode 100644 src/app/views/admin/hardware_profiles/create.haml
 create mode 100644 src/app/views/admin/hardware_profiles/edit.haml
 create mode 100644 src/app/views/admin/hardware_profiles/new.haml

diff --git a/src/app/controllers/admin/hardware_profiles_controller.rb b/src/app/controllers/admin/hardware_profiles_controller.rb
index 92edab0..f2b7e0f 100644
--- a/src/app/controllers/admin/hardware_profiles_controller.rb
+++ b/src/app/controllers/admin/hardware_profiles_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,7 +1,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 class Admin::HardwareProfilesController &amp;lt; ApplicationController
   before_filter :require_user
   before_filter :set_params_and_header, :only =&amp;gt; [:index, :show]
-  before_filter :load_hardware_profiles, :only =&amp;gt; [:show]
+  before_filter :load_hardware_profiles, :only =&amp;gt; [:index, :show]
+  before_filter :load_hardware_profile, :only =&amp;gt; [:show]
+  before_filter :setup_new_hardware_profile, :only =&amp;gt; [:new]
+  before_filter :setup_hardware_profile, :only =&amp;gt; [:new, :create, :edit, :update]
 
   def index
     &amp;lt; at &amp;gt;params = params
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -39,7 +42,77 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::HardwareProfilesController &amp;lt; ApplicationController
     end
   end
 
+  def new
+  end
+
+  def create
+    build_hardware_profile(params[:hardware_profile])
+    if params[:commit] == 'Save'
+      if &amp;lt; at &amp;gt;hardware_profile.save!
+        redirect_to admin_hardware_profiles_path
+      else
+        params.delete :commit
+        render :action =&amp;gt; 'create'
+      end
+    else
+      matching_provider_hardware_profiles
+      render :action =&amp;gt; 'new'
+    end
+  end
+
+  def delete
+  end
+
+  def edit
+    unless &amp;lt; at &amp;gt;hardware_profile
+      &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.find(params[:id])
+    end
+    matching_provider_hardware_profiles
+  end
+
+  def update
+    if params[:commit] == "Reset"
+      redirect_to edit_admin_hardware_profile_url(&amp;lt; at &amp;gt;hardware_profile) and return
+    end
+
+    if params[:id]
+      &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.find(params[:id])
+      build_hardware_profile(params[:hardware_profile])
+    end
+
+    if params[:commit] == "Check Matches"
+      matching_provider_hardware_profiles
+      render :edit and return
+    end
+
+    unless &amp;lt; at &amp;gt;hardware_profile.save!
+      render :action =&amp;gt; 'edit' and return
+    else
+      flash[:notice] = "Hardware Profile updated!"
+      redirect_to admin_hardware_profiles_path
+    end
+  end
+
+  def multi_destroy
+    HardwareProfile.destroy(params[:hardware_profile_selected])
+    redirect_to admin_hardware_profiles_path
+  end
+
   private
+  def setup_new_hardware_profile
+    if params[:hardware_profile]
+      begin
+        &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.new(remove_irrelevant_params(params[:hardware_profile]))
+      end
+    else
+      &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.new(:memory =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "memory", :unit =&amp;gt; "MB"),
+                                              :cpu =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "cpu", :unit =&amp;gt; "count"),
+                                              :storage =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "storage", :unit =&amp;gt; "GB"),
+                                              :architecture =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "architecture", :unit =&amp;gt; "label"))
+    end
+    matching_provider_hardware_profiles
+  end
+
   def properties
     &amp;lt; at &amp;gt;properties_header = [
       { :name =&amp;gt; "Name", :sort_attr =&amp;gt; :name},
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -63,8 +136,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::HardwareProfilesController &amp;lt; ApplicationController
       { :name =&amp;gt; "Storage", :sort_attr =&amp;gt; :storage },
       { :name =&amp;gt; "Virtual CPU", :sort_attr =&amp;gt; :cpus}
     ]
-    &amp;lt; at &amp;gt;matching_hwps = HardwareProfile.all(:include =&amp;gt; "aggregator_hardware_profiles",
-                                         :conditions =&amp;gt; {:hardware_profile_map =&amp;gt; { :aggregator_hardware_profile_id =&amp;gt; params[:id] }})
+
+    begin
+      &amp;lt; at &amp;gt;matching_hwps = HardwareProfile.matching_hwps(&amp;lt; at &amp;gt;hardware_profile).map { |hwp| hwp[:hardware_profile] }
+    rescue
+      &amp;lt; at &amp;gt;matching_hwps = []
+    end
+  end
+
+  def setup_hardware_profile
+    &amp;lt; at &amp;gt;tab_captions = ['Matched Provider Hardware Profiles']
+    &amp;lt; at &amp;gt;details_tab = 'matching_provider_hardware_profiles'
+    &amp;lt; at &amp;gt;url_params = params
+    &amp;lt; at &amp;gt;header  = [
+      { :name =&amp;gt; "Name", :sort_attr =&amp;gt; :name},
+      { :name =&amp;gt; "Unit", :sort_attr =&amp;gt; :unit},
+      { :name =&amp;gt; "Kind", :sort_attr =&amp;gt; :kind },
+      { :name =&amp;gt; "Value (Default)", :sort_attr =&amp;gt; :value},
+      { :name =&amp;gt; "Enum Entries", :sort_attr =&amp;gt; :false },
+      { :name =&amp;gt; "Range First", :sort_attr =&amp;gt; :range_first},
+      { :name =&amp;gt; "Range Last", :sort_attr =&amp;gt; :range_last }]
   end
 
   def set_params_and_header
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -81,4 +172,42 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::HardwareProfilesController &amp;lt; ApplicationController
   def load_hardware_profiles
     &amp;lt; at &amp;gt;hardware_profiles = HardwareProfile.all(:conditions =&amp;gt; 'provider_id IS NULL')
   end
+
+  def load_hardware_profile
+    &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.find(params[:id])
+  end
+
+  def build_hardware_profile(params)
+    hwpps = [:memory_attributes, :cpu_attributes, :storage_attributes, :architecture_attributes]
+    enum_values = {}
+    hwpps.each do |attr|
+      unless params[attr][:kind] == "range"
+        params[attr].delete(:range_first)
+        params[attr].delete(:range_last)
+      end
+
+      unless params[attr][:kind] == "enum"
+        params[attr].delete(:enum)
+      else
+        enum_values[params[attr][:name]] = params[attr][:property_enum_entries].split(%r{,\s*})
+      end
+      params[attr].delete(:property_enum_entries)
+    end
+
+    &amp;lt; at &amp;gt;hardware_profile.nil? ? &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.new(params) : &amp;lt; at &amp;gt;hardware_profile.update_attributes(params)
+    &amp;lt; at &amp;gt;hardware_profile.save!
+
+    # Set Property Enum Entries on enum types
+    begin
+      [&amp;lt; at &amp;gt;hardware_profile.memory, &amp;lt; at &amp;gt;hardware_profile.cpu, &amp;lt; at &amp;gt;hardware_profile.architecture, &amp;lt; at &amp;gt;hardware_profile.storage].each do |hwpp|
+        if hwpp.kind == "enum"
+          hwpp.property_enum_entries = enum_values[hwpp.name].map { |value| PropertyEnumEntry.new(:value =&amp;gt; value) }
+        end
+      end
+      &amp;lt; at &amp;gt;hardware_profile.save!
+    rescue =&amp;gt; e
+      &amp;lt; at &amp;gt;hardware_profile.delete!
+      raise e
+    end
+  end
 end
diff --git a/src/app/models/hardware_profile.rb b/src/app/models/hardware_profile.rb
index 5e6e9e8..22dc5c4 100644
--- a/src/app/models/hardware_profile.rb
+++ b/src/app/models/hardware_profile.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -41,13 +41,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfile &amp;lt; ActiveRecord::Base
 
   belongs_to :memory,       :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
+
   belongs_to :storage,      :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
+
   belongs_to :cpu,          :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
+
   belongs_to :architecture, :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
 
+  accepts_nested_attributes_for :memory, :cpu, :storage, :architecture
+
   has_and_belongs_to_many :aggregator_hardware_profiles,
                           :class_name =&amp;gt; "HardwareProfile",
                           :join_table =&amp;gt; "hardware_profile_map",
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -60,8 +65,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfile &amp;lt; ActiveRecord::Base
                           :foreign_key =&amp;gt; "aggregator_hardware_profile_id",
                           :association_foreign_key =&amp;gt; "provider_hardware_profile_id"
 
-  validates_presence_of :external_key
-  validates_uniqueness_of :external_key, :scope =&amp;gt; [:provider_id]
+  #validates_presence_of :external_key
+  #validates_uniqueness_of :external_key, :scope =&amp;gt; [:provider_id]
 
   validates_presence_of :name
   validates_uniqueness_of :name, :scope =&amp;gt; [:provider_id]
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -79,8 +84,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfile &amp;lt; ActiveRecord::Base
   def validate
     if provider.nil?
       if !aggregator_hardware_profiles.empty?
-        errors.add(:aggregator_hardware_profiles,
-                   "Aggregator profiles only allowed for provider profiles")
+        #errors.add(:aggregator_hardware_profiles,
+                   #"Aggregator profiles only allowed for provider profiles")
       end
     else
       if !provider_hardware_profiles.empty?
diff --git a/src/app/models/hardware_profile_property.rb b/src/app/models/hardware_profile_property.rb
index 46e4b8e..3f6bdfe 100644
--- a/src/app/models/hardware_profile_property.rb
+++ b/src/app/models/hardware_profile_property.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -101,7 +101,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfileProperty &amp;lt; ActiveRecord::Base
   def to_s
     case kind
       when FIXED
-        value
+        value.to_s
       when RANGE
         range_first.to_s + " - " + range_last.to_s
       when ENUM
diff --git a/src/app/models/property_enum_entry.rb b/src/app/models/property_enum_entry.rb
index ff497ef..81bb67e 100644
--- a/src/app/models/property_enum_entry.rb
+++ b/src/app/models/property_enum_entry.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -32,4 +32,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PropertyEnumEntry &amp;lt; ActiveRecord::Base
                                      HardwareProfileProperty::STORAGE or
                                  p.hardware_profile_property.name ==
                                    HardwareProfileProperty::CPU }
+  def to_s
+    value.to_s + ", "
+  end
 end
diff --git a/src/app/stylesheets/newui.scss b/src/app/stylesheets/newui.scss
index 513d510..d0fbcc9 100644
--- a/src/app/stylesheets/newui.scss
+++ b/src/app/stylesheets/newui.scss
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1371,6 +1371,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; $content-left: 180px;
   float: left;
 }
 
+#list {
+  float: left;
+  width: 100%;
+}
+
 #details-view {
   border: 1px solid;
   position: absolute;
diff --git a/src/app/views/admin/hardware_profiles/_form.haml b/src/app/views/admin/hardware_profiles/_form.haml
new file mode 100644
index 0000000..65278f2
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/_form.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,28 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+=hwp_form.label :name
+=hwp_form.text_field :name
+%table
+  = sortable_table_header &amp;lt; at &amp;gt;header
+  - [:memory, :cpu, :storage, :architecture].each do |type|
+    - hwp_form.fields_for type do |hwpp_form|
+      %tr
+        %td
+          =hwpp_form.text_field(:name, :readonly =&amp;gt; "readonly")
+        %td
+          =hwpp_form.text_field(:unit, :size =&amp;gt; 5, :readonly =&amp;gt; "readonly")
+        %td
+          -unless type == :architecture
+            =hwpp_form.select("kind", ["fixed", "range", "enum"], {})
+          -else
+            =hwpp_form.select("kind", ["fixed", "enum"], {})
+        %td
+          =hwpp_form.text_field(:value)
+        %td
+          =hwpp_form.text_field(:property_enum_entries)
+        %td
+          -unless type == :architecture
+            =hwpp_form.text_field(:range_first)
+        %td
+          -unless type == :architecture
+            =hwpp_form.text_field(:range_last)
+= hwp_form.submit 'Check Matches', :class =&amp;gt; "submit formbutton"
+= hwp_form.submit 'Save', :class =&amp;gt; 'submit formbutton'
\ No newline at end of file
diff --git a/src/app/views/admin/hardware_profiles/_list.haml b/src/app/views/admin/hardware_profiles/_list.haml
index 1001db3..e2f344e 100644
--- a/src/app/views/admin/hardware_profiles/_list.haml
+++ b/src/app/views/admin/hardware_profiles/_list.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 - form_tag do
   #object-actions
+    = link_to "New Hardware Profile", new_admin_hardware_profile_path, :class =&amp;gt; 'button'
+    = restful_submit_tag "Delete", "destroy", multi_destroy_admin_hardware_profiles_path, "DELETE", :id =&amp;gt; 'delete_button'
 
   #selections
     %p
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -8,19 +10,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
       %span&amp;gt; ,&amp;amp;nbsp;
       = link_to "None", &amp;lt; at &amp;gt;url_params.merge(:select =&amp;gt; 'none')
 
-%table
-  = sortable_table_header &amp;lt; at &amp;gt;header
-  - &amp;lt; at &amp;gt;hardware_profiles.each do |hwp|
-    %tr
-      %td
-        - selected = &amp;lt; at &amp;gt;url_params[:select] == 'all'
-        = check_box(:pool, "selected[#{hwp.id}]", :checked =&amp;gt; selected)
-        = link_to hwp.name, admin_hardware_profile_path(hwp)
-      %td
-        =hwp.architecture.to_s
-      %td
-        =hwp.memory.to_s
-      %td
-        =hwp.storage.to_s
-      %td
-        =hwp.cpu.to_s
+  #list
+    %table
+      = sortable_table_header &amp;lt; at &amp;gt;header
+      - &amp;lt; at &amp;gt;hardware_profiles.each do |hwp|
+        %tr
+          %td
+            - selected = &amp;lt; at &amp;gt;url_params[:select] == 'all'
+            %input{:name =&amp;gt; "hardware_profile_selected[]", :type =&amp;gt; "checkbox", :value =&amp;gt; hwp.id, :id =&amp;gt; "hardware_profile_checkbox_#{hwp.id}", :checked =&amp;gt; selected }
+            = link_to hwp.name, admin_hardware_profile_path(hwp)
+          %td
+            =hwp.architecture.to_s
+          %td
+            =hwp.memory.to_s
+          %td
+            =hwp.storage.to_s
+          %td
+            =hwp.cpu.to_s
diff --git a/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml b/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml
index cfbb856..0f4ba7b 100644
--- a/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml
+++ b/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,11 +1,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-%h3
-  = &amp;lt; at &amp;gt;hardware_profile.name
+- if &amp;lt; at &amp;gt;hardware_profile
+  %h3
+    =&amp;lt; at &amp;gt;hardware_profile.name
 %table
   = sortable_table_header &amp;lt; at &amp;gt;provider_hwps_header
   - &amp;lt; at &amp;gt;matching_hwps.each do |hwp|
     %tr
       %td
-        = link_to hwp.provider.name, admin_provider_path(hwp.provider)
+        - if hwp.provider
+          = link_to hwp.provider.name, admin_provider_path(hwp.provider)
       %td
         = link_to hwp.name, admin_hardware_profile_path(hwp)
       %td
diff --git a/src/app/views/admin/hardware_profiles/_properties.haml b/src/app/views/admin/hardware_profiles/_properties.haml
index 590edc5..bc91219 100644
--- a/src/app/views/admin/hardware_profiles/_properties.haml
+++ b/src/app/views/admin/hardware_profiles/_properties.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 %h3
   = &amp;lt; at &amp;gt;hardware_profile.name + "(" + (&amp;lt; at &amp;gt;hardware_profile.provider_id.nil? ? "Front End" : "Provider" ) + ")"
+= link_to 'Edit', edit_admin_hardware_profile_path(&amp;lt; at &amp;gt;hardware_profile), :class =&amp;gt; 'button'
 %table
   = sortable_table_header &amp;lt; at &amp;gt;properties_header
   - &amp;lt; at &amp;gt;hwp_properties.each do |hwpp|
diff --git a/src/app/views/admin/hardware_profiles/create.haml b/src/app/views/admin/hardware_profiles/create.haml
new file mode 100644
index 0000000..c26bbe9
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/create.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+%h3
+  Check Matching Hardware Profiles
+- content_for :list do
+  = render :partial =&amp;gt; "form"
+- content_for :details do
+  = render :partial =&amp;gt; 'layouts/details_pane'
\ No newline at end of file
diff --git a/src/app/views/admin/hardware_profiles/edit.haml b/src/app/views/admin/hardware_profiles/edit.haml
new file mode 100644
index 0000000..e32eebd
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/edit.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+- content_for :list do
+  %h3
+    Edit Hardware Profile
+  -form_for &amp;lt; at &amp;gt;hardware_profile, :url =&amp;gt; admin_hardware_profile_path(&amp;lt; at &amp;gt;hardware_profile), :html =&amp;gt; { :multipart =&amp;gt; true } do |hwp_form|
+    = render :partial =&amp;gt; "form", :locals =&amp;gt; { :hwp_form =&amp;gt; hwp_form }
+- content_for :details do
+  = render :partial =&amp;gt; 'layouts/details_pane'
diff --git a/src/app/views/admin/hardware_profiles/new.haml b/src/app/views/admin/hardware_profiles/new.haml
new file mode 100644
index 0000000..3355c87
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/new.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+- content_for :list do
+  %h3
+    New Hardware Profile
+  -form_for &amp;lt; at &amp;gt;hardware_profile, :url =&amp;gt; admin_hardware_profiles_path, :html =&amp;gt; { :multipart =&amp;gt; true } do |hwp_form|
+    = render :partial =&amp;gt; "form", :locals =&amp;gt; { :hwp_form =&amp;gt; hwp_form }
+- content_for :details do
+  = render :partial =&amp;gt; 'layouts/details_pane'
\ No newline at end of file
diff --git a/src/app/views/admin/provider_accounts/new.haml b/src/app/views/admin/provider_accounts/new.haml
index e567bce..55e469c 100644
--- a/src/app/views/admin/provider_accounts/new.haml
+++ b/src/app/views/admin/provider_accounts/new.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -13,4 +13,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
       %p.requirement
         %span.required *
         \-
-        = t('cloud_accounts.new.required_field')
+        = t('cloud_accounts.new.required_field')
\ No newline at end of file
diff --git a/src/config/routes.rb b/src/config/routes.rb
index ad9fb67..ba5109e 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -49,6 +49,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ActionController::Routing::Routes.draw do |map|
 
   map.namespace 'admin' do |r|
     r.resources :hardware_profiles, :realms
+    r.resources :hardware_profiles, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
+    r.resources :pool_families, :realms
     r.resources :providers, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
     r.resources :users, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
     r.resources :provider_accounts, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
diff --git a/src/db/migrate/20090804135630_create_hardware_profiles.rb b/src/db/migrate/20090804135630_create_hardware_profiles.rb
index 5ad0435..ec4a50f 100644
--- a/src/db/migrate/20090804135630_create_hardware_profiles.rb
+++ b/src/db/migrate/20090804135630_create_hardware_profiles.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -40,7 +40,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CreateHardwareProfiles &amp;lt; ActiveRecord::Migration
     end
 
     create_table :hardware_profiles do |t|
-      t.string  :external_key, :null =&amp;gt; false
+      t.string  :external_key
       t.string  :name, :null =&amp;gt; false, :limit =&amp;gt; 1024
       t.integer :memory_id
       t.integer :storage_id
diff --git a/src/features/hardware_profile.feature b/src/features/hardware_profile.feature
index 5f63c96..9c0572d 100644
--- a/src/features/hardware_profile.feature
+++ b/src/features/hardware_profile.feature
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -77,3 +77,63 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; Feature: Manage Pools
     Then I should see "m1-small"
     And I should not see "m1-large"
     And I should not see "m1-xlarge"
+
+  Scenario: Create a new Hardware Profile
+    Given I am an authorised user
+    And I am on the hardware profiles page
+    When I follow "New Hardware Profile"
+    Then I should be on the new hardware profile page
+    When I fill in "name" with "Test Hardware Profile"
+    And I enter the following details for the Hardware Profile Properties
+    | name         | kind  | range_first | range_last | property_enum_entries | value         | unit  |
+    | memory       | fixed |             |            |                       | 1740          | MB    |
+    | cpu          | range | 1           | 4          |                       | 2             | count |
+    | storage      | range | 250         | 500        |                       | 300           | GB    |
+    | architecture | enum  |             |            | i386, x86_64          | i386          | label |
+    And I press "Save"
+    Then I should be on the hardware profiles page
+    And I should see the following:
+    | Test Hardware Profile | 1740   | 1 - 4 | 250 - 500 | i386, x86_64 |
+
+  Scenario: Check New Hardware Profile matching Provider Hardware Profiles
+    Given I am an authorised user
+    And there are the following provider hardware profiles:
+    | name         | memory | cpu |storage  | architecture |
+    | m1-small     | 1740   | 1   | 250     | i386         |
+    | m1-medium    | 1740   | 2   | 500     | i386         |
+    | m1-large     | 2048   | 4   | 850     | x86_64       |
+    And I am on the new hardware profile page
+    When I fill in "name" with "Test Hardware Profile"
+    And I enter the following details for the Hardware Profile Properties
+    | name         | kind  | range_first | range_last | property_enum_entries | value         | unit  |
+    | memory       | fixed |             |            |                       | 1740          | MB    |
+    | cpu          | range | 1           | 4          |                       | 2             | count |
+    | storage      | range | 250         | 500        |                       | 300           | GB    |
+    | architecture | enum  |             |            | i386, x86_64          | i386          | label |
+    And I press "Check Matches"
+    Then I should see the following:
+    | Name         | Memory | CPU | Storage | Architecture |
+    | m1-small     | 1740   | 1   | 250     | i386         |
+    | m1-medium    | 1740   | 2   | 500     | i386         |
+
+  Scenario: Update a HardwareProfile
+    Given I am an authorised user
+    And there are the following aggregator hardware profiles:
+    | name     | memory | cpu |storage  | architecture |
+    | m1-small | 1740   | 2   | 160     | i386         |
+    And I am on the hardware profiles page
+    When I follow "m1-small"
+    Then I should see "Properties"
+    When I follow "edit"
+    Then I should be on the edit hardware profiles page
+    When I enter the following details for the Hardware Profile Properties
+    | name         | kind  | range_first | range_last | property_enum_entries | value         |
+    | memory       | fixed |             |            |                       | 1740          |
+    | cpu          | range | 1           | 4          |                       | 1             |
+    | storage      | range | 250         | 500        |                       | 300           |
+    | architecture | enum  |             |            | i386, x86_64          | i386          |
+    And I press "Save"
+    Then I should be on the hardware profiles page
+    Then I should see the following:
+    | Name         | Memory | CPU       | Storage   | Architecture |
+    | m1-small     | 1740   | 1 - 4     | 250 - 500 | i386, x86_64 |
diff --git a/src/features/step_definitions/hardware_profile_steps.rb b/src/features/step_definitions/hardware_profile_steps.rb
index d29d136..9a8ecbf 100644
--- a/src/features/step_definitions/hardware_profile_steps.rb
+++ b/src/features/step_definitions/hardware_profile_steps.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,4 +19,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; def create_hwp(hash, provider=nil)
   cpu = Factory(:mock_hwp1_cpu, :value =&amp;gt; hash[:cpu])
   arch = Factory(:mock_hwp1_arch, :value =&amp;gt; hash[:architecture])
   Factory(:mock_hwp1, :name =&amp;gt; hash[:name], :memory =&amp;gt; memory, :cpu =&amp;gt; cpu, :storage =&amp;gt; storage, :architecture =&amp;gt; arch, :provider =&amp;gt; provider)
+end
+
+When /^I enter the following details for the Hardware Profile Properties$/ do |table|
+  table.hashes.each do |hash|
+    hash.each_pair do |key, value|
+      unless (hash[:name] == "architecture" &amp;amp;&amp;amp; (key == "range_first" || key == "range_last")) || key == "name"
+        When "I fill in \"#{"hardware_profile_" + hash[:name] + "_attributes_" + key}\" with \"#{value}\""
+      end
+    end
+  end
+end
+
+Given /^there are the following provider hardware profiles:$/ do |table|
+  provider = Factory :mock_provider
+  table.hashes.each do |hash|
+    create_hwp(hash, provider)
+  end
 end
\ No newline at end of file
diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb
index c0c77dc..4bc7ba4 100644
--- a/src/features/support/paths.rb
+++ b/src/features/support/paths.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -98,6 +98,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; module NavigationHelpers
     when /the hardware profiles page/
       url_for admin_hardware_profiles_path
 
+    when /the new hardware profile page/
+      url_for new_admin_hardware_profile_path
+
+    when /the edit hardware profiles page/
+      url_for :action =&amp;gt; 'edit', :controller =&amp;gt; 'hardware_profiles', :only_path =&amp;gt; true
+
     when /^(.*)'s provider account page$/
       admin_provider_account_path(CloudAccount.find_by_label($1))
 
&lt;/pre&gt;</description>
    <dc:creator>mtaylor-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-17T14:08:37</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3697">
    <title>[PATCH aeolus] Hardware Profiles UI</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3697</link>
    <description>&lt;pre&gt;From: Martyn Taylor &amp;lt;mtaylor-H+wXaHxf7aLQT0dZR+AlfA&amp;lt; at &amp;gt;public.gmane.org&amp;gt;

---
 .../admin/hardware_profiles_controller.rb          |  114 +++++++++++++++++++-
 src/app/models/hardware_profile.rb                 |   13 ++-
 src/app/models/hardware_profile_property.rb        |    2 +-
 src/app/models/property_enum_entry.rb              |    3 +
 src/app/stylesheets/newui.scss                     |    5 +
 src/app/views/admin/hardware_profiles/_form.haml   |   28 +++++
 src/app/views/admin/hardware_profiles/_list.haml   |   37 ++++---
 .../_matching_provider_hardware_profiles.haml      |    8 +-
 .../views/admin/hardware_profiles/_properties.haml |    1 +
 src/app/views/admin/hardware_profiles/create.haml  |    6 +
 src/app/views/admin/hardware_profiles/edit.haml    |    7 ++
 src/app/views/admin/hardware_profiles/new.haml     |    7 ++
 src/app/views/admin/provider_accounts/new.haml     |    2 +-
 src/config/routes.rb                               |    3 +-
 .../20090804135630_create_hardware_profiles.rb     |    2 +-
 src/features/hardware_profile.feature              |   63 +++++++++++-
 .../step_definitions/hardware_profile_steps.rb     |   21 ++++
 src/features/support/paths.rb                      |    6 +
 18 files changed, 295 insertions(+), 33 deletions(-)
 create mode 100644 src/app/views/admin/hardware_profiles/_form.haml
 create mode 100644 src/app/views/admin/hardware_profiles/create.haml
 create mode 100644 src/app/views/admin/hardware_profiles/edit.haml
 create mode 100644 src/app/views/admin/hardware_profiles/new.haml

diff --git a/src/app/controllers/admin/hardware_profiles_controller.rb b/src/app/controllers/admin/hardware_profiles_controller.rb
index 67c655d..b57bd37 100644
--- a/src/app/controllers/admin/hardware_profiles_controller.rb
+++ b/src/app/controllers/admin/hardware_profiles_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,6 +2,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::HardwareProfilesController &amp;lt; ApplicationController
   before_filter :require_user
   before_filter :load_hardware_profiles, :only =&amp;gt; [:index, :show]
   before_filter :load_hardware_profile, :only =&amp;gt; [:show]
+  before_filter :setup_new_hardware_profile, :only =&amp;gt; [:new]
+  before_filter :setup_hardware_profile, :only =&amp;gt; [:new, :create, :edit, :update]
+
   def index
   end
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -29,12 +32,73 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::HardwareProfilesController &amp;lt; ApplicationController
   end
 
   def create
+    build_hardware_profile(params[:hardware_profile])
+    if params[:commit] == 'Save'
+      if &amp;lt; at &amp;gt;hardware_profile.save!
+        redirect_to admin_hardware_profiles_path
+      else
+        params.delete :commit
+        render :action =&amp;gt; 'create'
+      end
+    else
+      matching_provider_hardware_profiles
+      render :action =&amp;gt; 'new'
+    end
   end
 
   def delete
   end
 
+  def edit
+    unless &amp;lt; at &amp;gt;hardware_profile
+      &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.find(params[:id])
+    end
+    matching_provider_hardware_profiles
+  end
+
+  def update
+    if params[:commit] == "Reset"
+      redirect_to edit_admin_hardware_profile_url(&amp;lt; at &amp;gt;hardware_profile) and return
+    end
+
+    if params[:id]
+      &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.find(params[:id])
+      build_hardware_profile(params[:hardware_profile])
+    end
+
+    if params[:commit] == "Check Matches"
+      matching_provider_hardware_profiles
+      render :edit and return
+    end
+
+    unless &amp;lt; at &amp;gt;hardware_profile.save!
+      render :action =&amp;gt; 'edit' and return
+    else
+      flash[:notice] = "Hardware Profile updated!"
+      redirect_to admin_hardware_profiles_path
+    end
+  end
+
+  def multi_destroy
+    HardwareProfile.destroy(params[:hardware_profile_selected])
+    redirect_to admin_hardware_profiles_path
+  end
+
   private
+  def setup_new_hardware_profile
+    if params[:hardware_profile]
+      begin
+        &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.new(remove_irrelevant_params(params[:hardware_profile]))
+      end
+    else
+      &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.new(:memory =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "memory", :unit =&amp;gt; "MB"),
+                                              :cpu =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "cpu", :unit =&amp;gt; "count"),
+                                              :storage =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "storage", :unit =&amp;gt; "GB"),
+                                              :architecture =&amp;gt; HardwareProfileProperty.new(:name =&amp;gt; "architecture", :unit =&amp;gt; "label"))
+    end
+    matching_provider_hardware_profiles
+  end
+
   def properties
     &amp;lt; at &amp;gt;properties_header = [
       { :name =&amp;gt; "Name", :sort_attr =&amp;gt; :name},
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -58,8 +122,26 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::HardwareProfilesController &amp;lt; ApplicationController
       { :name =&amp;gt; "Storage", :sort_attr =&amp;gt; :storage },
       { :name =&amp;gt; "Virtual CPU", :sort_attr =&amp;gt; :cpus}
     ]
-    &amp;lt; at &amp;gt;matching_hwps = HardwareProfile.all(:include =&amp;gt; "aggregator_hardware_profiles",
-                                         :conditions =&amp;gt; {:hardware_profile_map =&amp;gt; { :aggregator_hardware_profile_id =&amp;gt; params[:id] }})
+
+    begin
+      &amp;lt; at &amp;gt;matching_hwps = HardwareProfile.matching_hwps(&amp;lt; at &amp;gt;hardware_profile).map { |hwp| hwp[:hardware_profile] }
+    rescue
+      &amp;lt; at &amp;gt;matching_hwps = []
+    end
+  end
+
+  def setup_hardware_profile
+    &amp;lt; at &amp;gt;tab_captions = ['Matched Provider Hardware Profiles']
+    &amp;lt; at &amp;gt;details_tab = 'matching_provider_hardware_profiles'
+    &amp;lt; at &amp;gt;url_params = params
+    &amp;lt; at &amp;gt;header  = [
+      { :name =&amp;gt; "Name", :sort_attr =&amp;gt; :name},
+      { :name =&amp;gt; "Unit", :sort_attr =&amp;gt; :unit},
+      { :name =&amp;gt; "Kind", :sort_attr =&amp;gt; :kind },
+      { :name =&amp;gt; "Value (Default)", :sort_attr =&amp;gt; :value},
+      { :name =&amp;gt; "Enum Entries", :sort_attr =&amp;gt; :false },
+      { :name =&amp;gt; "Range First", :sort_attr =&amp;gt; :range_first},
+      { :name =&amp;gt; "Range Last", :sort_attr =&amp;gt; :range_last }]
   end
 
   def load_hardware_profiles
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -75,7 +157,33 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class Admin::HardwareProfilesController &amp;lt; ApplicationController
   end
 
   def load_hardware_profile
-    &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.find((params[:id] || []).first)
+    &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.find(params[:id])
   end
 
+  def build_hardware_profile(params)
+    hwpps = [:memory_attributes, :cpu_attributes, :storage_attributes, :architecture_attributes]
+    enum_values = {}
+    hwpps.each do |attr|
+      unless params[attr][:kind] == "range"
+        params[attr].delete(:range_first)
+        params[attr].delete(:range_last)
+      end
+
+      unless params[attr][:kind] == "enum"
+        params[attr].delete(:enum)
+      else
+        enum_values[params[attr][:name]] = params[attr][:property_enum_entries].split(%r{,\s*})
+      end
+      params[attr].delete(:property_enum_entries)
+    end
+
+    &amp;lt; at &amp;gt;hardware_profile.nil? ? &amp;lt; at &amp;gt;hardware_profile = HardwareProfile.new(params) : &amp;lt; at &amp;gt;hardware_profile.update_attributes(params)
+
+    # Set Property Enum Entries on enum types
+    [&amp;lt; at &amp;gt;hardware_profile.memory, &amp;lt; at &amp;gt;hardware_profile.cpu, &amp;lt; at &amp;gt;hardware_profile.architecture, &amp;lt; at &amp;gt;hardware_profile.storage].each do |hwpp|
+      if hwpp.kind == "enum"
+        hwpp.property_enum_entries = enum_values[hwpp.name].map { |value| PropertyEnumEntry.new(:value =&amp;gt; value) }
+      end
+    end
+  end
 end
\ No newline at end of file
diff --git a/src/app/models/hardware_profile.rb b/src/app/models/hardware_profile.rb
index d7ae995..10f1283 100644
--- a/src/app/models/hardware_profile.rb
+++ b/src/app/models/hardware_profile.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -29,13 +29,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfile &amp;lt; ActiveRecord::Base
 
   belongs_to :memory,       :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
+
   belongs_to :storage,      :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
+
   belongs_to :cpu,          :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
+
   belongs_to :architecture, :class_name =&amp;gt; "HardwareProfileProperty",
                             :dependent =&amp;gt; :destroy
 
+  accepts_nested_attributes_for :memory, :cpu, :storage, :architecture
+
   has_and_belongs_to_many :aggregator_hardware_profiles,
                           :class_name =&amp;gt; "HardwareProfile",
                           :join_table =&amp;gt; "hardware_profile_map",
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -48,8 +53,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfile &amp;lt; ActiveRecord::Base
                           :foreign_key =&amp;gt; "aggregator_hardware_profile_id",
                           :association_foreign_key =&amp;gt; "provider_hardware_profile_id"
 
-  validates_presence_of :external_key
-  validates_uniqueness_of :external_key, :scope =&amp;gt; [:provider_id]
+  #validates_presence_of :external_key
+  #validates_uniqueness_of :external_key, :scope =&amp;gt; [:provider_id]
 
   validates_presence_of :name
   validates_uniqueness_of :name, :scope =&amp;gt; [:provider_id]
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -67,8 +72,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfile &amp;lt; ActiveRecord::Base
   def validate
     if provider.nil?
       if !aggregator_hardware_profiles.empty?
-        errors.add(:aggregator_hardware_profiles,
-                   "Aggregator profiles only allowed for provider profiles")
+        #errors.add(:aggregator_hardware_profiles,
+                   #"Aggregator profiles only allowed for provider profiles")
       end
     else
       if !provider_hardware_profiles.empty?
diff --git a/src/app/models/hardware_profile_property.rb b/src/app/models/hardware_profile_property.rb
index 46e4b8e..3f6bdfe 100644
--- a/src/app/models/hardware_profile_property.rb
+++ b/src/app/models/hardware_profile_property.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -101,7 +101,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class HardwareProfileProperty &amp;lt; ActiveRecord::Base
   def to_s
     case kind
       when FIXED
-        value
+        value.to_s
       when RANGE
         range_first.to_s + " - " + range_last.to_s
       when ENUM
diff --git a/src/app/models/property_enum_entry.rb b/src/app/models/property_enum_entry.rb
index ff497ef..81bb67e 100644
--- a/src/app/models/property_enum_entry.rb
+++ b/src/app/models/property_enum_entry.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -32,4 +32,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class PropertyEnumEntry &amp;lt; ActiveRecord::Base
                                      HardwareProfileProperty::STORAGE or
                                  p.hardware_profile_property.name ==
                                    HardwareProfileProperty::CPU }
+  def to_s
+    value.to_s + ", "
+  end
 end
diff --git a/src/app/stylesheets/newui.scss b/src/app/stylesheets/newui.scss
index 513d510..d0fbcc9 100644
--- a/src/app/stylesheets/newui.scss
+++ b/src/app/stylesheets/newui.scss
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1371,6 +1371,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; $content-left: 180px;
   float: left;
 }
 
+#list {
+  float: left;
+  width: 100%;
+}
+
 #details-view {
   border: 1px solid;
   position: absolute;
diff --git a/src/app/views/admin/hardware_profiles/_form.haml b/src/app/views/admin/hardware_profiles/_form.haml
new file mode 100644
index 0000000..65278f2
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/_form.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,28 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+=hwp_form.label :name
+=hwp_form.text_field :name
+%table
+  = sortable_table_header &amp;lt; at &amp;gt;header
+  - [:memory, :cpu, :storage, :architecture].each do |type|
+    - hwp_form.fields_for type do |hwpp_form|
+      %tr
+        %td
+          =hwpp_form.text_field(:name, :readonly =&amp;gt; "readonly")
+        %td
+          =hwpp_form.text_field(:unit, :size =&amp;gt; 5, :readonly =&amp;gt; "readonly")
+        %td
+          -unless type == :architecture
+            =hwpp_form.select("kind", ["fixed", "range", "enum"], {})
+          -else
+            =hwpp_form.select("kind", ["fixed", "enum"], {})
+        %td
+          =hwpp_form.text_field(:value)
+        %td
+          =hwpp_form.text_field(:property_enum_entries)
+        %td
+          -unless type == :architecture
+            =hwpp_form.text_field(:range_first)
+        %td
+          -unless type == :architecture
+            =hwpp_form.text_field(:range_last)
+= hwp_form.submit 'Check Matches', :class =&amp;gt; "submit formbutton"
+= hwp_form.submit 'Save', :class =&amp;gt; 'submit formbutton'
\ No newline at end of file
diff --git a/src/app/views/admin/hardware_profiles/_list.haml b/src/app/views/admin/hardware_profiles/_list.haml
index 7399549..e2f344e 100644
--- a/src/app/views/admin/hardware_profiles/_list.haml
+++ b/src/app/views/admin/hardware_profiles/_list.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,7 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 - form_tag do
   #object-actions
-    = restful_submit_tag "Create", "create", admin_hardware_profiles_path, "PUT"
-    = restful_submit_tag "Delete", "delete", admin_hardware_profiles_path, "DELETE"
+    = link_to "New Hardware Profile", new_admin_hardware_profile_path, :class =&amp;gt; 'button'
+    = restful_submit_tag "Delete", "destroy", multi_destroy_admin_hardware_profiles_path, "DELETE", :id =&amp;gt; 'delete_button'
 
   #selections
     %p
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -10,19 +10,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
       %span&amp;gt; ,&amp;amp;nbsp;
       = link_to "None", &amp;lt; at &amp;gt;url_params.merge(:select =&amp;gt; 'none')
 
-%table
-  = sortable_table_header &amp;lt; at &amp;gt;header
-  - &amp;lt; at &amp;gt;hardware_profiles.each do |hwp|
-    %tr
-      %td
-        - selected = &amp;lt; at &amp;gt;url_params[:select] == 'all'
-        = check_box(:pool, "selected[#{hwp.id}]", :checked =&amp;gt; selected)
-        = link_to hwp.name, admin_hardware_profile_path(hwp)
-      %td
-        =hwp.architecture.to_s
-      %td
-        =hwp.memory.to_s
-      %td
-        =hwp.storage.to_s
-      %td
-        =hwp.cpu.to_s
+  #list
+    %table
+      = sortable_table_header &amp;lt; at &amp;gt;header
+      - &amp;lt; at &amp;gt;hardware_profiles.each do |hwp|
+        %tr
+          %td
+            - selected = &amp;lt; at &amp;gt;url_params[:select] == 'all'
+            %input{:name =&amp;gt; "hardware_profile_selected[]", :type =&amp;gt; "checkbox", :value =&amp;gt; hwp.id, :id =&amp;gt; "hardware_profile_checkbox_#{hwp.id}", :checked =&amp;gt; selected }
+            = link_to hwp.name, admin_hardware_profile_path(hwp)
+          %td
+            =hwp.architecture.to_s
+          %td
+            =hwp.memory.to_s
+          %td
+            =hwp.storage.to_s
+          %td
+            =hwp.cpu.to_s
diff --git a/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml b/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml
index cfbb856..0f4ba7b 100644
--- a/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml
+++ b/src/app/views/admin/hardware_profiles/_matching_provider_hardware_profiles.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,11 +1,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-%h3
-  = &amp;lt; at &amp;gt;hardware_profile.name
+- if &amp;lt; at &amp;gt;hardware_profile
+  %h3
+    =&amp;lt; at &amp;gt;hardware_profile.name
 %table
   = sortable_table_header &amp;lt; at &amp;gt;provider_hwps_header
   - &amp;lt; at &amp;gt;matching_hwps.each do |hwp|
     %tr
       %td
-        = link_to hwp.provider.name, admin_provider_path(hwp.provider)
+        - if hwp.provider
+          = link_to hwp.provider.name, admin_provider_path(hwp.provider)
       %td
         = link_to hwp.name, admin_hardware_profile_path(hwp)
       %td
diff --git a/src/app/views/admin/hardware_profiles/_properties.haml b/src/app/views/admin/hardware_profiles/_properties.haml
index 590edc5..bc91219 100644
--- a/src/app/views/admin/hardware_profiles/_properties.haml
+++ b/src/app/views/admin/hardware_profiles/_properties.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 %h3
   = &amp;lt; at &amp;gt;hardware_profile.name + "(" + (&amp;lt; at &amp;gt;hardware_profile.provider_id.nil? ? "Front End" : "Provider" ) + ")"
+= link_to 'Edit', edit_admin_hardware_profile_path(&amp;lt; at &amp;gt;hardware_profile), :class =&amp;gt; 'button'
 %table
   = sortable_table_header &amp;lt; at &amp;gt;properties_header
   - &amp;lt; at &amp;gt;hwp_properties.each do |hwpp|
diff --git a/src/app/views/admin/hardware_profiles/create.haml b/src/app/views/admin/hardware_profiles/create.haml
new file mode 100644
index 0000000..c26bbe9
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/create.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+%h3
+  Check Matching Hardware Profiles
+- content_for :list do
+  = render :partial =&amp;gt; "form"
+- content_for :details do
+  = render :partial =&amp;gt; 'layouts/details_pane'
\ No newline at end of file
diff --git a/src/app/views/admin/hardware_profiles/edit.haml b/src/app/views/admin/hardware_profiles/edit.haml
new file mode 100644
index 0000000..e32eebd
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/edit.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+- content_for :list do
+  %h3
+    Edit Hardware Profile
+  -form_for &amp;lt; at &amp;gt;hardware_profile, :url =&amp;gt; admin_hardware_profile_path(&amp;lt; at &amp;gt;hardware_profile), :html =&amp;gt; { :multipart =&amp;gt; true } do |hwp_form|
+    = render :partial =&amp;gt; "form", :locals =&amp;gt; { :hwp_form =&amp;gt; hwp_form }
+- content_for :details do
+  = render :partial =&amp;gt; 'layouts/details_pane'
diff --git a/src/app/views/admin/hardware_profiles/new.haml b/src/app/views/admin/hardware_profiles/new.haml
new file mode 100644
index 0000000..3355c87
--- /dev/null
+++ b/src/app/views/admin/hardware_profiles/new.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+- content_for :list do
+  %h3
+    New Hardware Profile
+  -form_for &amp;lt; at &amp;gt;hardware_profile, :url =&amp;gt; admin_hardware_profiles_path, :html =&amp;gt; { :multipart =&amp;gt; true } do |hwp_form|
+    = render :partial =&amp;gt; "form", :locals =&amp;gt; { :hwp_form =&amp;gt; hwp_form }
+- content_for :details do
+  = render :partial =&amp;gt; 'layouts/details_pane'
\ No newline at end of file
diff --git a/src/app/views/admin/provider_accounts/new.haml b/src/app/views/admin/provider_accounts/new.haml
index e567bce..55e469c 100644
--- a/src/app/views/admin/provider_accounts/new.haml
+++ b/src/app/views/admin/provider_accounts/new.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -13,4 +13,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
       %p.requirement
         %span.required *
         \-
-        = t('cloud_accounts.new.required_field')
+        = t('cloud_accounts.new.required_field')
\ No newline at end of file
diff --git a/src/config/routes.rb b/src/config/routes.rb
index 6d9b5cf..463031d 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -47,7 +47,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ActionController::Routing::Routes.draw do |map|
   map.connect '/set_layout', :controller =&amp;gt; 'application', :action =&amp;gt; 'set_layout'
 
   map.namespace 'admin' do |r|
-    r.resources :hardware_profiles, :pool_families, :realms
+    r.resources :hardware_profiles, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
+    r.resources :pool_families, :realms
     r.resources :providers, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
     r.resources :users, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
     r.resources :provider_accounts, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
diff --git a/src/db/migrate/20090804135630_create_hardware_profiles.rb b/src/db/migrate/20090804135630_create_hardware_profiles.rb
index 5ad0435..ec4a50f 100644
--- a/src/db/migrate/20090804135630_create_hardware_profiles.rb
+++ b/src/db/migrate/20090804135630_create_hardware_profiles.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -40,7 +40,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; class CreateHardwareProfiles &amp;lt; ActiveRecord::Migration
     end
 
     create_table :hardware_profiles do |t|
-      t.string  :external_key, :null =&amp;gt; false
+      t.string  :external_key
       t.string  :name, :null =&amp;gt; false, :limit =&amp;gt; 1024
       t.integer :memory_id
       t.integer :storage_id
diff --git a/src/features/hardware_profile.feature b/src/features/hardware_profile.feature
index 6f1cc81..e6fa89e 100644
--- a/src/features/hardware_profile.feature
+++ b/src/features/hardware_profile.feature
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -48,4 +48,65 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; Feature: Manage Pools
     And I follow "Matching Provider Hardware Profiles"
     Then I should see the following:
     | Name      | Memory | CPU | Storage  | Architecture |
-    | m1-small  | 1740   | 2   | 160      | i386         |
\ No newline at end of file
+    | m1-small  | 1740   | 2   | 160      | i386         |
+
+  Scenario: Create a new Hardware Profile
+    Given I am an authorised user
+    And I am on the hardware profiles page
+    When I follow "New Hardware Profile"
+    Then I should be on the new hardware profile page
+    When I fill in "name" with "Test Hardware Profile"
+    And I enter the following details for the Hardware Profile Properties
+    | name         | kind  | range_first | range_last | property_enum_entries | value         | unit  |
+    | memory       | fixed |             |            |                       | 1740          | MB    |
+    | cpu          | range | 1           | 4          |                       | 2             | count |
+    | storage      | range | 250         | 500        |                       | 300           | GB    |
+    | architecture | enum  |             |            | i386, x86_64          | i386          | label |
+    And I press "Save"
+    Then I should be on the hardware profiles page
+    And I should see the following:
+    | Name                  | memory | cpu   | storage   | architecture |
+    | Test Hardware Profile | 1740   | 1 - 4 | 250 - 500 | i386, x86_64 |
+
+  Scenario: Check New Hardware Profile matching Provider Hardware Profiles
+    Given I am an authorised user
+    And there are the following provider hardware profiles:
+    | name      | memory | cpu |storage  | architecture |
+    | small     | 1740   | 1   | 250     | i386         |
+    | medium    | 1740   | 2   | 500     | i386         |
+    | large     | 2048   | 4   | 850     | x86_64       |
+    And I am on the new hardware profile page
+    When I fill in "name" with "Test Hardware Profile"
+    And I enter the following details for the Hardware Profile Properties
+    | name         | kind  | range_first | range_last | property_enum_entries | value         | unit  |
+    | memory       | fixed |             |            |                       | 1740          | MB    |
+    | cpu          | range | 1           | 4          |                       | 2             | count |
+    | storage      | range | 250         | 500        |                       | 300           | GB    |
+    | architecture | enum  |             |            | i386, x86_64          | i386          | label |
+    And I press "Check Matches"
+    Then I should see the following:
+    | Name      | Memory | CPU | Storage | Architecture |
+    | small     | 1740   | 1   | 300     | i386         |
+    | medium    | 1740   | 2   | 500     | i386         |
+
+  Scenario: Update a HardwareProfile
+    Given I am an authorised user
+    And there are the following aggregator hardware profiles:
+    | name     | memory | cpu |storage  | architecture |
+    | m1-small | 1740   | 2   | 160     | i386         |
+    And I am on the hardware profiles page
+    When I follow "m1-small"
+    Then I should see "Properties"
+    When I follow "edit"
+    Then I should be on the edit hardware profiles page
+    When I enter the following details for the Hardware Profile Properties
+    | name         | kind  | range_first | range_last | property_enum_entries | value         |
+    | memory       | fixed |             |            |                       | 1740          |
+    | cpu          | range | 1           | 4          |                       | 1             |
+    | storage      | range | 250         | 500        |                       | 300           |
+    | architecture | enum  |             |            | i386, x86_64          | i386          |
+    And I press "Save"
+    Then I should be on the hardware profiles page
+    Then I should see the following:
+    | Name         | Memory | CPU       | Storage   | Architecture |
+    | m1-small     | 1740   | 1 - 4     | 250 - 500 | i386, x86_64 |
\ No newline at end of file
diff --git a/src/features/step_definitions/hardware_profile_steps.rb b/src/features/step_definitions/hardware_profile_steps.rb
index d29d136..8965517 100644
--- a/src/features/step_definitions/hardware_profile_steps.rb
+++ b/src/features/step_definitions/hardware_profile_steps.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,4 +19,25 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; def create_hwp(hash, provider=nil)
   cpu = Factory(:mock_hwp1_cpu, :value =&amp;gt; hash[:cpu])
   arch = Factory(:mock_hwp1_arch, :value =&amp;gt; hash[:architecture])
   Factory(:mock_hwp1, :name =&amp;gt; hash[:name], :memory =&amp;gt; memory, :cpu =&amp;gt; cpu, :storage =&amp;gt; storage, :architecture =&amp;gt; arch, :provider =&amp;gt; provider)
+end
+
+When /^I enter the following details for the Hardware Profile Properties$/ do |table|
+  table.hashes.each do |hash|
+    hash.each_pair do |key, value|
+      unless (hash[:name] == "architecture" &amp;amp;&amp;amp; (key == "range_first" || key == "range_last")) || key == "name"
+        When "I fill in \"#{"hardware_profile_" + hash[:name] + "_attributes_" + key}\" with \"#{value}\""
+      end
+    end
+  end
+end
+
+Given /^there are the following provider hardware profiles:$/ do |table|
+  provider = Factory :mock_provider
+  table.hashes do |hash|
+    memory = Factory(:mock_hwp1_memory, :value =&amp;gt; hash[:memory])
+    cpu = Factory(:mock_hwp1_cpu, :value =&amp;gt; hash[:cpu])
+    storage = Factory(:mock_hwp1_storage, :value =&amp;gt; hash[:storage])
+    architecture = Factory(:mock_hwp1_architecture, :value =&amp;gt; hash[:architecture])
+    Factory(:hardware_profile, :provider =&amp;gt; provider, :memory =&amp;gt; memory, :storage =&amp;gt; storage, :cpu =&amp;gt; cpu, :architecture =&amp;gt; architecture)
+  end
 end
\ No newline at end of file
diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb
index 66de0d2..5dd1116 100644
--- a/src/features/support/paths.rb
+++ b/src/features/support/paths.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -98,6 +98,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; module NavigationHelpers
     when /the hardware profiles page/
       url_for admin_hardware_profiles_path
 
+    when /the new hardware profile page/
+      url_for new_admin_hardware_profile_path
+
+    when /the edit hardware profiles page/
+      url_for :action =&amp;gt; 'edit', :controller =&amp;gt; 'hardware_profiles', :only_path =&amp;gt; true
+
     when /^(.*)'s provider account page$/
       admin_provider_account_path(CloudAccount.find_by_label($1))
 
&lt;/pre&gt;</description>
    <dc:creator>mtaylor-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-17T12:08:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3689">
    <title>[PATCH 0/2]: Remove bogus references</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3689</link>
    <description>&lt;pre&gt;As mother always said, late is better than never.  Since we are in the process
of renaming the whole project, I figured that I would remove any references
to absolutely ancient things.  This series does that.

I did a run of these through the cucumber tests, and no new errors popped up.
That doesn't mean that they are perfect, just that they should be relatively
safe to commit.  Please review and ACK.
&lt;/pre&gt;</description>
    <dc:creator>Chris Lalancette</dc:creator>
    <dc:date>2011-01-14T20:00:56</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3688">
    <title>[PATCH aeolus] Cucumber tests for Users search</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3688</link>
    <description>&lt;pre&gt;From: Tomas Sedovic &amp;lt;tsedovic-H+wXaHxf7aLQT0dZR+AlfA&amp;lt; at &amp;gt;public.gmane.org&amp;gt;

---
 src/features/step_definitions/user_steps.rb |    4 +++-
 src/features/user.feature                   |   15 +++++++++++++++
 2 files changed, 18 insertions(+), 1 deletions(-)

diff --git a/src/features/step_definitions/user_steps.rb b/src/features/step_definitions/user_steps.rb
index ed474e3..13932fa 100644
--- a/src/features/step_definitions/user_steps.rb
+++ b/src/features/step_definitions/user_steps.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 Given /^there is a user "([^"]*)"$/ do |name|
-  User.find_by_login(name).should_not == nil
+  unless User.find_by_login(name)
+    Factory :user, :login =&amp;gt; name, :email =&amp;gt; "#{name}&amp;lt; at &amp;gt;example.com"
+  end
 end
 
 Given /^there are (\d+) users$/ do |number|
diff --git a/src/features/user.feature b/src/features/user.feature
index 89dd7d5..1819cb5 100644
--- a/src/features/user.feature
+++ b/src/features/user.feature
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -42,3 +42,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; Feature: Manage Users
     When I follow "cancel"
     Then there should only be 2 users
     And I should be on the admin users page
+
+  Scenario: Search for hardware profiles
+    Given there is a user "myuser"
+    And there is a user "someuser"
+    And I am on the admin users page
+    Then I should see "myuser"
+    And I should see "someuser"
+    When I fill in "q" with "some"
+    And I press "Search"
+    Then I should see "someuser"
+    And I should not see "myuser"
+    When I fill in "q" with "myuser"
+    And I press "Search"
+    Then I should see "myuser"
+    And I should not see "someuser"
&lt;/pre&gt;</description>
    <dc:creator>tsedovic-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-14T14:22:55</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3686">
    <title>[PATCH aeolus] Add search for Users</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3686</link>
    <description>&lt;pre&gt;From: Tomas Sedovic &amp;lt;tsedovic-H+wXaHxf7aLQT0dZR+AlfA&amp;lt; at &amp;gt;public.gmane.org&amp;gt;

---
 src/app/controllers/admin/users_controller.rb |   16 +++++++++++++++-
 src/app/models/user.rb                        |    7 +++++++
 2 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/src/app/controllers/admin/users_controller.rb b/src/app/controllers/admin/users_controller.rb
index 0e854a9..1c48dcb 100644
--- a/src/app/controllers/admin/users_controller.rb
+++ b/src/app/controllers/admin/users_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,7 +1,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 class Admin::UsersController &amp;lt; ApplicationController
   before_filter :require_user
   before_filter :only_admin, :only =&amp;gt; [:index, :multi_destroy]
-  before_filter :load_users, :only =&amp;gt; [:index, :show]
+  before_filter :load_users, :only =&amp;gt; [:show]
+
+  def index
+    &amp;lt; at &amp;gt;params = params
+    &amp;lt; at &amp;gt;search_term = params[:q]
+    if &amp;lt; at &amp;gt;search_term.blank?
+      load_users
+      return
+    end
+
+    search = User.search do
+      keywords(params[:q])
+    end
+    &amp;lt; at &amp;gt;users = search.results
+  end
 
   def new
     &amp;lt; at &amp;gt;user = User.new
diff --git a/src/app/models/user.rb b/src/app/models/user.rb
index 7942ae4..cc77d9d 100644
--- a/src/app/models/user.rb
+++ b/src/app/models/user.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,7 +19,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # Filters added to this controller apply to all controllers in the application.
 # Likewise, all the methods added will be available for all controllers.
 
+require 'sunspot_rails'
 class User &amp;lt; ActiveRecord::Base
+  searchable do
+    text :login, :as =&amp;gt; :code_substring
+    text :last_name, :as =&amp;gt; :code_substring
+    text :first_name, :as =&amp;gt; :code_substring
+    text :email, :as =&amp;gt; :code_substring
+  end
   acts_as_authentic
 
   has_many :permissions
&lt;/pre&gt;</description>
    <dc:creator>tsedovic-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-14T12:24:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3685">
    <title>[PATCH aggregator] Implement Assemblies basic UI</title>
    <link>http://comments.gmane.org/gmane.comp.lib.deltacloud.devel/3685</link>
    <description>&lt;pre&gt;From: Ladislav Martincik &amp;lt;lmartinc-H+wXaHxf7aLQT0dZR+AlfA&amp;lt; at &amp;gt;public.gmane.org&amp;gt;

---
 .../image_factory/assemblies_controller.rb         |   63 ++++++++++++++++++++
 src/app/models/assembly.rb                         |    2 +
 src/app/views/image_factory/assemblies/_form.haml  |    7 ++
 src/app/views/image_factory/assemblies/_list.haml  |   28 +++++++++
 .../image_factory/assemblies/_properties.haml      |    4 +
 src/app/views/image_factory/assemblies/edit.haml   |    4 +
 src/app/views/image_factory/assemblies/index.haml  |    3 +-
 src/app/views/image_factory/assemblies/new.haml    |    3 +
 src/app/views/image_factory/assemblies/show.haml   |    5 ++
 src/config/routes.rb                               |    2 +-
 src/db/migrate/20110114111158_create_assemblies.rb |   13 ++++
 src/features/assembly.feature                      |   50 ++++++++++++++++
 src/features/step_definitions/assembly_steps.rb    |   20 ++++++
 src/features/support/paths.rb                      |    3 +
 14 files changed, 205 insertions(+), 2 deletions(-)
 create mode 100644 src/app/models/assembly.rb
 create mode 100644 src/app/views/image_factory/assemblies/_form.haml
 create mode 100644 src/app/views/image_factory/assemblies/_list.haml
 create mode 100644 src/app/views/image_factory/assemblies/_properties.haml
 create mode 100644 src/app/views/image_factory/assemblies/edit.haml
 create mode 100644 src/app/views/image_factory/assemblies/new.haml
 create mode 100644 src/app/views/image_factory/assemblies/show.haml
 create mode 100644 src/db/migrate/20110114111158_create_assemblies.rb
 create mode 100644 src/features/assembly.feature
 create mode 100644 src/features/step_definitions/assembly_steps.rb

diff --git a/src/app/controllers/image_factory/assemblies_controller.rb b/src/app/controllers/image_factory/assemblies_controller.rb
index ce67f14..6627656 100644
--- a/src/app/controllers/image_factory/assemblies_controller.rb
+++ b/src/app/controllers/image_factory/assemblies_controller.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,6 +1,69 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 class ImageFactory::AssembliesController &amp;lt; ApplicationController
   before_filter :require_user
+  before_filter :load_assemblies, :only =&amp;gt; [:index, :show]
 
   def index
   end
+
+  def show
+    &amp;lt; at &amp;gt;assembly = Assembly.find(params[:id])
+    &amp;lt; at &amp;gt;url_params = params.clone
+    &amp;lt; at &amp;gt;tab_captions = ['Properties']
+    &amp;lt; at &amp;gt;details_tab = params[:details_tab].blank? ? 'properties' : params[:details_tab]
+    respond_to do |format|
+      format.js do
+        if &amp;lt; at &amp;gt;url_params.delete :details_pane
+          render :partial =&amp;gt; 'layouts/details_pane' and return
+        end
+        render :partial =&amp;gt; &amp;lt; at &amp;gt;details_tab and return
+      end
+      format.html { render :action =&amp;gt; 'show'}
+    end
+  end
+
+  def new
+    &amp;lt; at &amp;gt;assembly = Assembly.new
+  end
+
+  def create
+    &amp;lt; at &amp;gt;assembly = Assembly.new(params[:assembly])
+    if &amp;lt; at &amp;gt;assembly.save
+      flash[:notice] = "Assembly added."
+      redirect_to image_factory_assembly_url(&amp;lt; at &amp;gt;assembly)
+    else
+      render :action =&amp;gt; :new
+    end
+  end
+
+  def edit
+    &amp;lt; at &amp;gt;assembly = Assembly.find(params[:id])
+  end
+
+  def update
+    &amp;lt; at &amp;gt;assembly = Assembly.find(params[:id])
+    if &amp;lt; at &amp;gt;assembly.update_attributes(params[:assembly])
+      flash[:notice] = "Assembly updated."
+      redirect_to image_factory_assembly_url(&amp;lt; at &amp;gt;assembly)
+    else
+      render :action =&amp;gt; :edit
+    end
+  end
+
+  def multi_destroy
+    Assembly.destroy(params[:assemblies_selected])
+    redirect_to image_factory_assemblies_url
+  end
+
+  protected
+
+  def load_assemblies
+    &amp;lt; at &amp;gt;header = [
+      { :name =&amp;gt; "Assembly name", :sort_attr =&amp;gt; :name }
+    ]
+    &amp;lt; at &amp;gt;assemblies = Assembly.paginate(:all,
+      :page =&amp;gt; params[:page] || 1,
+      :order =&amp;gt; (params[:order_field] || 'name') +' '+ (params[:order_dir] || 'asc')
+    )
+    &amp;lt; at &amp;gt;url_params = params.clone
+  end
 end
diff --git a/src/app/models/assembly.rb b/src/app/models/assembly.rb
new file mode 100644
index 0000000..5eac9de
--- /dev/null
+++ b/src/app/models/assembly.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,2 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+class Assembly &amp;lt; ActiveRecord::Base
+end
diff --git a/src/app/views/image_factory/assemblies/_form.haml b/src/app/views/image_factory/assemblies/_form.haml
new file mode 100644
index 0000000..39556e5
--- /dev/null
+++ b/src/app/views/image_factory/assemblies/_form.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+= form.error_messages
+%fieldset.clear
+  = form.label :name, t(:name), :class =&amp;gt; "grid_3 alpha"
+  = form.text_field :name, :class =&amp;gt; "grid_5"
+%fieldset.clearfix
+  = form.submit "Save",  :class =&amp;gt; "submit formbutton"
+  = link_to t(:cancel), image_factory_assemblies_path, :class =&amp;gt; 'button formbutton'
diff --git a/src/app/views/image_factory/assemblies/_list.haml b/src/app/views/image_factory/assemblies/_list.haml
new file mode 100644
index 0000000..f29b322
--- /dev/null
+++ b/src/app/views/image_factory/assemblies/_list.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,28 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+- form_tag do
+  = link_to "Create", new_image_factory_assembly_url, :class =&amp;gt; 'button'
+  = restful_submit_tag "Delete", 'destroy', multi_destroy_image_factory_assemblies_path, 'DELETE', :id =&amp;gt; 'delete_button'
+
+  %table#assemblies_table
+    %thead
+      %tr
+        %th
+        %th= link_to "Name", image_factory_assemblies_url(:sort_by =&amp;gt; "name")
+    -&amp;lt; at &amp;gt;assemblies.each do |assembly|
+      %tr
+        %td
+          %input{:name =&amp;gt; "assemblies_selected[]", :type =&amp;gt; "checkbox", :value =&amp;gt; assembly.id, :id =&amp;gt; "assembly_checkbox_#{assembly.id}" }
+        %td= link_to assembly.name, image_factory_assembly_path(assembly)
+
+:javascript
+  $(document).ready(function () {
+    $('#delete_button').click(function(e) {
+      if ($("#assemblies_table input[&amp;lt; at &amp;gt;type=radio]:checked").length == 0) {
+        alert('Please select any assembly to be deleted before clicking Delete button.');
+        e.preventDefault();
+      } else {
+        if (!confirm("Are you sure you want to delete this assembly?")) {
+          e.preventDefault();
+        }
+      }
+    });
+  });
diff --git a/src/app/views/image_factory/assemblies/_properties.haml b/src/app/views/image_factory/assemblies/_properties.haml
new file mode 100644
index 0000000..5f91f6e
--- /dev/null
+++ b/src/app/views/image_factory/assemblies/_properties.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+.grid_13
+  %h2 #{&amp;lt; at &amp;gt;assembly.name}
+
+  = link_to 'Edit', edit_image_factory_assembly_path(&amp;lt; at &amp;gt;assembly), :class =&amp;gt; 'button'
diff --git a/src/app/views/image_factory/assemblies/edit.haml b/src/app/views/image_factory/assemblies/edit.haml
new file mode 100644
index 0000000..04871c3
--- /dev/null
+++ b/src/app/views/image_factory/assemblies/edit.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+%h2 Editing Assembly: #{&amp;lt; at &amp;gt;assembly.name}
+
+- form_for &amp;lt; at &amp;gt;assembly, :url =&amp;gt; image_factory_assembly_path(&amp;lt; at &amp;gt;assembly), :html =&amp;gt; { :method =&amp;gt; :put } do |f|
+  = render :partial =&amp;gt; "form", :locals =&amp;gt; { :form =&amp;gt; f }
diff --git a/src/app/views/image_factory/assemblies/index.haml b/src/app/views/image_factory/assemblies/index.haml
index 766d92c..62ccbc6 100644
--- a/src/app/views/image_factory/assemblies/index.haml
+++ b/src/app/views/image_factory/assemblies/index.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1 +1,2 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-image_factory/assemblies/index.haml
+- content_for :list do
+  = render :partial =&amp;gt; 'list'
diff --git a/src/app/views/image_factory/assemblies/new.haml b/src/app/views/image_factory/assemblies/new.haml
new file mode 100644
index 0000000..4763405
--- /dev/null
+++ b/src/app/views/image_factory/assemblies/new.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,3 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+%h2 New Assembly
+- form_for &amp;lt; at &amp;gt;assembly, :url =&amp;gt; image_factory_assemblies_path do |f|
+  = render :partial =&amp;gt; "form", :locals =&amp;gt; { :form =&amp;gt; f }
diff --git a/src/app/views/image_factory/assemblies/show.haml b/src/app/views/image_factory/assemblies/show.haml
new file mode 100644
index 0000000..05eeedd
--- /dev/null
+++ b/src/app/views/image_factory/assemblies/show.haml
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,5 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+- content_for :list do
+  = render :partial =&amp;gt; 'list'
+
+- content_for :details do
+  = render :partial =&amp;gt; 'layouts/details_pane'
diff --git a/src/config/routes.rb b/src/config/routes.rb
index ad9fb67..00aaade 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -39,7 +39,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ActionController::Routing::Routes.draw do |map|
   end
 
   map.namespace 'image_factory' do |r|
-    r.resources :assemblies
+    r.resources :assemblies, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
     r.resources :deployables, :collection =&amp;gt; { :multi_destroy =&amp;gt; :delete }
     r.resources :templates, :collection =&amp;gt; {:collections =&amp;gt; :get, :add_selected =&amp;gt; :get, :metagroup_packages =&amp;gt; :get, :remove_package =&amp;gt; :get, :multi_destroy =&amp;gt; :delete}
     r.resources :builds
diff --git a/src/db/migrate/20110114111158_create_assemblies.rb b/src/db/migrate/20110114111158_create_assemblies.rb
new file mode 100644
index 0000000..25aaf7b
--- /dev/null
+++ b/src/db/migrate/20110114111158_create_assemblies.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+class CreateAssemblies &amp;lt; ActiveRecord::Migration
+  def self.up
+    create_table :assemblies do |t|
+      t.string :name
+
+      t.timestamps
+    end
+  end
+
+  def self.down
+    drop_table :assemblies
+  end
+end
diff --git a/src/features/assembly.feature b/src/features/assembly.feature
new file mode 100644
index 0000000..970f1b5
--- /dev/null
+++ b/src/features/assembly.feature
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,50 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+Feature: Manage assemblies
+  In order to manage my cloud infrastructure
+  As a user
+  I want to manage assemblies
+
+  Background:
+    Given I am an authorised user
+    And I am logged in
+    And I am using new UI
+
+  Scenario: List assemblies
+    Given I am on the homepage
+    And there is a assembly named "MySQL cluster"
+    When I go to the image factory assemblies page
+    Then I should see "MySQL cluster"
+
+  Scenario: Create a new Assembly
+    Given there is a assembly named "MySQL cluster"
+    And I am on the image factory assemblies page
+    When I follow "Create"
+    Then I should be on the new image factory assembly page
+    And I should see "New Assembly"
+    When I fill in "assembly[name]" with "App"
+    And I press "Save"
+    Then I should be on App's image factory assembly page
+    And I should see "Assembly added"
+    And I should have a assembly named "App"
+    And I should see "App"
+
+  Scenario: Edit a assembly
+    Given there is a assembly named "MySQL cluster"
+    And I am on the image factory assemblies page
+    When I follow "MySQL cluster"
+    And I follow "Edit"
+    Then I should be on the edit image factory assembly page
+    And I should see "Editing Assembly"
+    When I fill in "assembly[name]" with "AppModified"
+    And I press "Save"
+    Then I should be on AppModified's image factory assembly page
+    And I should see "Assembly updated"
+    And I should have a assembly named "AppModified"
+    And I should see "AppModified"
+
+  Scenario: Delete a assembly
+    Given there is a assembly named "App"
+    And I am on the image factory assemblies page
+    When I check the "App" assembly
+    And I press "Delete"
+    Then I should be on the image factory assemblies page
+    And there should be no assemblies
diff --git a/src/features/step_definitions/assembly_steps.rb b/src/features/step_definitions/assembly_steps.rb
new file mode 100644
index 0000000..cb9c5f0
--- /dev/null
+++ b/src/features/step_definitions/assembly_steps.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+Then /^there should be no assemblies$/ do
+  Assembly.count.should == 0
+end
+
+Given /^there are no assemblies$/ do
+  Assembly.count.should == 0
+end
+
+Then /^I should have a assembly named "([^"]*)"$/ do |name|
+  Assembly.find_by_name(name).should_not be_nil
+end
+
+Given /^there is a assembly named "([^"]*)"$/ do |name|
+  Assembly.create!(:name =&amp;gt; name)
+end
+
+When /^I check the "([^"]*)" assembly$/ do |name|
+  assembly = Assembly.find_by_name(name)
+  check("assembly_checkbox_#{assembly.id}")
+end
diff --git a/src/features/support/paths.rb b/src/features/support/paths.rb
index c0c77dc..dbe0077 100644
--- a/src/features/support/paths.rb
+++ b/src/features/support/paths.rb
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -104,6 +104,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; module NavigationHelpers
     when /^(.*)'s image factory deployable page$/
       image_factory_deployable_path(Deployable.find_by_name($1))
 
+    when /^(.*)'s image factory assembly page$/
+      image_factory_assembly_path(Assembly.find_by_name($1))
+
     # Add more mappings here.
     # Here is an example that pulls values out of the Regexp:
     #
&lt;/pre&gt;</description>
    <dc:creator>lmartinc-H+wXaHxf7aLQT0dZR+AlfA&lt; at &gt;public.gmane.org</dc:creator>
    <dc:date>2011-01-14T11:45:11</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.comp.lib.deltacloud.devel">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.comp.lib.deltacloud.devel</link>
  </textinput>
</rdf:RDF>

