New UI for Roles
by Tomas Hrcka
- this patch requires jtomasek's patch Task #1712
12 years, 11 months
New UI for Realm
by jzigmund@redhat.com
Patch needs to be applied on jtomasek's patch (New UI elements for Administration section part1, you can use also NACKed patch)
12 years, 11 months
[PATCH] New UI elements for Administration section part1
by Jirka Tomasek
From: Jiri Tomasek <jtomasek(a)redhat.com>
Addded new ui elements for Index views in Administration section
---
src/app/views/hardware_profiles/_list.haml | 59 +++++++++++---------
.../views/hardware_profiles/_section_header.haml | 5 ++
src/app/views/hardware_profiles/index.haml | 4 +-
src/app/views/layouts/_admin_header.haml | 9 +---
src/app/views/pool_families/_list.haml | 47 +++++++++-------
src/app/views/pool_families/_section_header.haml | 5 ++
src/app/views/pool_families/index.haml | 4 +-
src/app/views/provider_accounts/_list.haml | 45 ++++++++-------
.../views/provider_accounts/_section_header.haml | 5 ++
src/app/views/provider_accounts/index.haml | 4 +-
src/app/views/providers/_list.haml | 41 ++++++++------
src/app/views/providers/_section_header.haml | 5 ++
src/app/views/providers/index.haml | 4 +-
src/app/views/providers/show.haml | 20 ++++++-
src/app/views/realms/_list.haml | 39 +++++++------
src/app/views/realms/_section_header.haml | 5 ++
src/app/views/realms/index.haml | 4 +-
src/app/views/roles/_list.haml | 37 +++++++-----
src/app/views/roles/_section_header.haml | 5 ++
src/app/views/roles/index.haml | 4 +-
src/features/pool_family.feature | 2 +-
src/features/provider.feature | 4 +-
src/features/provider_account.feature | 6 +-
src/features/realm.feature | 2 +-
24 files changed, 217 insertions(+), 148 deletions(-)
create mode 100644 src/app/views/hardware_profiles/_section_header.haml
create mode 100644 src/app/views/pool_families/_section_header.haml
create mode 100644 src/app/views/provider_accounts/_section_header.haml
create mode 100644 src/app/views/providers/_section_header.haml
create mode 100644 src/app/views/realms/_section_header.haml
create mode 100644 src/app/views/roles/_section_header.haml
diff --git a/src/app/views/hardware_profiles/_list.haml b/src/app/views/hardware_profiles/_list.haml
index bbca7a6..808ae2a 100644
--- a/src/app/views/hardware_profiles/_list.haml
+++ b/src/app/views/hardware_profiles/_list.haml
@@ -1,28 +1,33 @@
-- form_tag do
- #object-actions
- = link_to "New Hardware Profile", new_hardware_profile_path, :class => 'button'
- = restful_submit_tag "Delete", 'destroy', multi_destroy_hardware_profiles_path, 'DELETE', :id => 'delete_button', :class => 'button'
- #selections
- %p
- Select:
- = link_to "All", @url_params.merge(:select => 'all')
- %span> ,
- = link_to "None", @url_params.merge(:select => 'none')
+%section.content-section.hardware_profiles
+ %header
+ %h2 Hardware Profiles
+ %span.label.badge.dark.count= @hardware_profiles.length
- #list
- %table
- = sortable_table_header @header
- - @hardware_profiles.each do |hwp|
- %tr
- %td
- - selected = @url_params[:select] == 'all'
- %input{:name => "hardware_profile_selected[]", :type => "checkbox", :value => hwp.id, :id => "hardware_profile_checkbox_#{hwp.id}", :checked => selected }
- = link_to hwp.name, hardware_profile_path(hwp)
- %td
- =hwp.architecture.to_s
- %td
- =hwp.memory.to_s
- %td
- =hwp.storage.to_s
- %td
- =hwp.cpu.to_s
+ .content
+ - form_tag do
+ #object-actions
+ = restful_submit_tag "Delete", 'destroy', multi_destroy_hardware_profiles_path, 'DELETE', :id => 'delete_button', :class => 'button'
+ #selections
+ %p
+ Select:
+ = link_to "All", @url_params.merge(:select => 'all')
+ %span> ,
+ = link_to "None", @url_params.merge(:select => 'none')
+
+ #list
+ %table
+ = sortable_table_header @header
+ - @hardware_profiles.each do |hwp|
+ %tr
+ %td
+ - selected = @url_params[:select] == 'all'
+ %input{:name => "hardware_profile_selected[]", :type => "checkbox", :value => hwp.id, :id => "hardware_profile_checkbox_#{hwp.id}", :checked => selected }
+ = link_to hwp.name, 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/hardware_profiles/_section_header.haml b/src/app/views/hardware_profiles/_section_header.haml
new file mode 100644
index 0000000..d5a975e
--- /dev/null
+++ b/src/app/views/hardware_profiles/_section_header.haml
@@ -0,0 +1,5 @@
+%header.page-header
+ %h1{:class => controller.controller_name} Hardware Profiles
+ #obj_actions.button-group
+ = link_to 'New Hardware Profile', new_hardware_profile_url, :class => 'button primary', :id => 'new_hardware_profile_button'
+ .corner
diff --git a/src/app/views/hardware_profiles/index.haml b/src/app/views/hardware_profiles/index.haml
index acfa09b..55fac46 100644
--- a/src/app/views/hardware_profiles/index.haml
+++ b/src/app/views/hardware_profiles/index.haml
@@ -1,3 +1,3 @@
= render :partial => 'layouts/admin_header'
-%div#view
- = render :partial => 'list'
+= render :partial => 'section_header'
+= render :partial => 'list'
diff --git a/src/app/views/layouts/_admin_header.haml b/src/app/views/layouts/_admin_header.haml
index 3b5c935..19834d5 100644
--- a/src/app/views/layouts/_admin_header.haml
+++ b/src/app/views/layouts/_admin_header.haml
@@ -18,16 +18,9 @@
%option{:value => pool_families_path} Pool Families
%option{:value => settings_path} Settings
-- unless controller.controller_name == 'users'
- %header.page-header
- %h1{:class => controller.controller_name}= controller.controller_name.titlecase
- -##obj_actions.button-group
- -#= link_to 'New Object', new_object_url, :class => 'button primary', :id => 'new_object_button'
- .corner
-
:javascript
$(document).ready(function() {
$('select#admin-section-select').change(function() {
window.location = $(this).val();
});
- });
\ No newline at end of file
+ });
diff --git a/src/app/views/pool_families/_list.haml b/src/app/views/pool_families/_list.haml
index 1133073..e6afe8e 100644
--- a/src/app/views/pool_families/_list.haml
+++ b/src/app/views/pool_families/_list.haml
@@ -1,23 +1,28 @@
-- form_tag do
- = link_to "Create", new_pool_family_path, :class => "button"
- = restful_submit_tag "Delete", 'destroy', multi_destroy_pool_families_path, 'DELETE', :id => 'delete_button', :class => 'button'
+%section.content-section.pool_families
+ %header
+ %h2 Pool Families
+ %span.label.badge.dark.count= @pool_families.length
- %p
- Select:
- = link_to "All", @url_params.merge(:select => 'all')
- %span> ,
- = link_to "None", @url_params.merge(:select => 'none')
+ .content
+ - form_tag do
+ = restful_submit_tag "Delete", 'destroy', multi_destroy_pool_families_path, 'DELETE', :id => 'delete_button', :class => 'button'
- %table#pool_families_table
- = sortable_table_header @header
- - unless @pool_families.blank?
- - @pool_families.each do |pool_family|
- %tr
- %td
- - selected = @url_params[:select] == 'all'
- %input{:name => "pool_family_selected[]", :type => "checkbox", :value => pool_family.id, :id => "pool_family_checkbox_#{pool_family.id}", :checked => selected }
- = link_to pool_family.name, pool_family_path(pool_family)
- %td
- = pool_family.quota.maximum_running_instances or 'unlimited'
- %td
- = "#{pool_family.quota.percentage_used} %"
+ %p
+ Select:
+ = link_to "All", @url_params.merge(:select => 'all')
+ %span> ,
+ = link_to "None", @url_params.merge(:select => 'none')
+
+ %table#pool_families_table
+ = sortable_table_header @header
+ - unless @pool_families.blank?
+ - @pool_families.each do |pool_family|
+ %tr
+ %td
+ - selected = @url_params[:select] == 'all'
+ %input{:name => "pool_family_selected[]", :type => "checkbox", :value => pool_family.id, :id => "pool_family_checkbox_#{pool_family.id}", :checked => selected }
+ = link_to pool_family.name, pool_family_path(pool_family)
+ %td
+ = pool_family.quota.maximum_running_instances or 'unlimited'
+ %td
+ = "#{pool_family.quota.percentage_used} %"
diff --git a/src/app/views/pool_families/_section_header.haml b/src/app/views/pool_families/_section_header.haml
new file mode 100644
index 0000000..8fb7cf3
--- /dev/null
+++ b/src/app/views/pool_families/_section_header.haml
@@ -0,0 +1,5 @@
+%header.page-header
+ %h1{:class => controller.controller_name} Pool Families
+ #obj_actions.button-group
+ = link_to 'New Pool Family', new_pool_family_url, :class => 'button primary', :id => 'new_pool_family_button'
+ .corner
diff --git a/src/app/views/pool_families/index.haml b/src/app/views/pool_families/index.haml
index acfa09b..55fac46 100644
--- a/src/app/views/pool_families/index.haml
+++ b/src/app/views/pool_families/index.haml
@@ -1,3 +1,3 @@
= render :partial => 'layouts/admin_header'
-%div#view
- = render :partial => 'list'
+= render :partial => 'section_header'
+= render :partial => 'list'
diff --git a/src/app/views/provider_accounts/_list.haml b/src/app/views/provider_accounts/_list.haml
index 5f598c8..8dfb3a0 100644
--- a/src/app/views/provider_accounts/_list.haml
+++ b/src/app/views/provider_accounts/_list.haml
@@ -1,20 +1,25 @@
-- form_tag do
- = link_to "New Account", new_provider_account_path, :class => 'button'
- = restful_submit_tag "Delete", "delete", multi_destroy_provider_accounts_path, 'DELETE', :class => 'button'
- %p
- Select:
- = link_to "All", @url_params.merge(:select => 'all')
- %span> ,
- = link_to "None", @url_params.merge(:select => 'none')
- %table
- = sortable_table_header @header
- - @accounts.each do |account|
- %tr
- %td
- - selected = @url_params[:select] == 'all'
- %input{:name => 'accounts_selected[]', :type => 'checkbox', :value => account.id, :id => "account_checkbox_#{account.id}", :checked => selected }
- = link_to account.name, provider_account_path(account)
- %td
- =account.credentials_hash['username']
- %td
- =account.provider.provider_type.name
+%section.content-section.users
+ %header
+ %h2 Provider Accounts
+ %span.label.badge.dark.count= @accounts.length
+
+ .content
+ - form_tag do
+ = restful_submit_tag "Delete", "delete", multi_destroy_provider_accounts_path, 'DELETE', :class => 'button'
+ %p
+ Select:
+ = link_to "All", @url_params.merge(:select => 'all')
+ %span> ,
+ = link_to "None", @url_params.merge(:select => 'none')
+ %table
+ = sortable_table_header @header
+ - @accounts.each do |account|
+ %tr
+ %td
+ - selected = @url_params[:select] == 'all'
+ %input{:name => 'accounts_selected[]', :type => 'checkbox', :value => account.id, :id => "account_checkbox_#{account.id}", :checked => selected }
+ = link_to account.name, provider_account_path(account)
+ %td
+ =account.credentials_hash['username']
+ %td
+ =account.provider.provider_type.name
diff --git a/src/app/views/provider_accounts/_section_header.haml b/src/app/views/provider_accounts/_section_header.haml
new file mode 100644
index 0000000..5ef520a
--- /dev/null
+++ b/src/app/views/provider_accounts/_section_header.haml
@@ -0,0 +1,5 @@
+%header.page-header
+ %h1{:class => controller.controller_name} Provider Accounts
+ #obj_actions.button-group
+ = link_to 'New Provider Account', new_provider_account_url, :class => 'button primary', :id => 'new_provider_account_button'
+ .corner
diff --git a/src/app/views/provider_accounts/index.haml b/src/app/views/provider_accounts/index.haml
index acfa09b..55fac46 100644
--- a/src/app/views/provider_accounts/index.haml
+++ b/src/app/views/provider_accounts/index.haml
@@ -1,3 +1,3 @@
= render :partial => 'layouts/admin_header'
-%div#view
- = render :partial => 'list'
+= render :partial => 'section_header'
+= render :partial => 'list'
diff --git a/src/app/views/providers/_list.haml b/src/app/views/providers/_list.haml
index 417b416..10abadd 100644
--- a/src/app/views/providers/_list.haml
+++ b/src/app/views/providers/_list.haml
@@ -1,20 +1,25 @@
-- form_tag do
- = link_to "Create", new_provider_url, :class => "button"
- = restful_submit_tag "Delete", 'destroy', multi_destroy_providers_path, 'DELETE', :id => 'delete_button', :class => 'button'
+%section.content-section.providers
+ %header
+ %h2 Providers
+ %span.label.badge.dark.count= @providers.length
- %p
- Select:
- = link_to "All", @url_params.merge(:select => 'all')
- %span> ,
- = link_to "None", @url_params.merge(:select => 'none')
+ .content
+ - form_tag do
+ = restful_submit_tag "Delete", 'destroy', multi_destroy_providers_path, 'DELETE', :id => 'delete_button', :class => 'button'
- %table#providers_table
- = sortable_table_header @header
- -(a)providers.each do |provider|
- %tr
- %td
- - selected = @url_params[:select] == 'all'
- %input{:name => "provider_selected[]", :type => "checkbox", :value => provider.id, :id => "provider_checkbox_#{provider.id}", :checked => selected }
- = link_to provider.name, provider_path(provider)
- %td= provider.url
- %td= provider.provider_type.name
+ %p
+ Select:
+ = link_to "All", @url_params.merge(:select => 'all')
+ %span> ,
+ = link_to "None", @url_params.merge(:select => 'none')
+
+ %table#providers_table
+ = sortable_table_header @header
+ -(a)providers.each do |provider|
+ %tr
+ %td
+ - selected = @url_params[:select] == 'all'
+ %input{:name => "provider_selected[]", :type => "checkbox", :value => provider.id, :id => "provider_checkbox_#{provider.id}", :checked => selected }
+ = link_to provider.name, provider_path(provider)
+ %td= provider.url
+ %td= provider.provider_type.name
diff --git a/src/app/views/providers/_section_header.haml b/src/app/views/providers/_section_header.haml
new file mode 100644
index 0000000..b667673
--- /dev/null
+++ b/src/app/views/providers/_section_header.haml
@@ -0,0 +1,5 @@
+%header.page-header
+ %h1{:class => controller.controller_name} Providers
+ #obj_actions.button-group
+ = link_to 'New Provider', new_provider_url, :class => 'button primary', :id => 'new_provider_button'
+ .corner
diff --git a/src/app/views/providers/index.haml b/src/app/views/providers/index.haml
index acfa09b..55fac46 100644
--- a/src/app/views/providers/index.haml
+++ b/src/app/views/providers/index.haml
@@ -1,3 +1,3 @@
= render :partial => 'layouts/admin_header'
-%div#view
- = render :partial => 'list'
+= render :partial => 'section_header'
+= render :partial => 'list'
diff --git a/src/app/views/providers/show.haml b/src/app/views/providers/show.haml
index 2eadbfd..c9313a5 100644
--- a/src/app/views/providers/show.haml
+++ b/src/app/views/providers/show.haml
@@ -1,3 +1,19 @@
= render :partial => 'layouts/admin_header'
-%div#view
- = render :partial => 'properties'
+%header.page-header
+ %h1{:class => controller.controller_name}= @provider.name
+ #obj_actions.button-container
+ = link_to 'New Provider', new_provider_url, :class => 'button primary', :id => 'new_provider_button'
+ %form.button-group{:action => provider_path(@provider), :method => 'POST'}
+ = link_to 'Edit', edit_provider_path(@provider), :class => 'button pill'
+ = link_to "Test", provider_path(@provider, {:test_provider => true}), { :class => 'button' }
+ %input{:name => "provider_selected[]", :type => "hidden", :value => @provider.id}
+ = restful_submit_tag('Delete', 'destroy', multi_destroy_providers_path, 'DELETE', :class => "button pill danger")
+ .corner
+
+%section.content-section.provider
+ %header
+ %h2 Properties
+
+ .content
+ %div#view
+ = render :partial => 'properties'
diff --git a/src/app/views/realms/_list.haml b/src/app/views/realms/_list.haml
index 2803e6a..054eb33 100644
--- a/src/app/views/realms/_list.haml
+++ b/src/app/views/realms/_list.haml
@@ -1,19 +1,24 @@
-- form_tag do
- = link_to "Create", new_realm_path, :class => "button"
- = restful_submit_tag "Delete", 'destroy', multi_destroy_realms_path, 'DELETE', :id => 'delete_button', :class => 'button'
+%section.content-section.realms
+ %header
+ %h2 Realms
+ %span.label.badge.dark.count= @realms.length
- %p
- Select:
- = link_to "All", @url_params.merge(:select => 'all')
- %span> ,
- = link_to "None", @url_params.merge(:select => 'none')
+ .content
+ - form_tag do
+ = restful_submit_tag "Delete", 'destroy', multi_destroy_realms_path, 'DELETE', :id => 'delete_button', :class => 'button'
- %table#realms_table
- = sortable_table_header @header
- - unless @realms.blank?
- - @realms.each do |realm|
- %tr
- %td
- - selected = @url_params[:select] == 'all'
- %input{:name => "id[]", :type => "checkbox", :value => realm.id, :id => "realm_id_#{realm.id}", :checked => selected }
- = link_to realm.name, realm_path(realm)
+ %p
+ Select:
+ = link_to "All", @url_params.merge(:select => 'all')
+ %span> ,
+ = link_to "None", @url_params.merge(:select => 'none')
+
+ %table#realms_table
+ = sortable_table_header @header
+ - unless @realms.blank?
+ - @realms.each do |realm|
+ %tr
+ %td
+ - selected = @url_params[:select] == 'all'
+ %input{:name => "id[]", :type => "checkbox", :value => realm.id, :id => "realm_id_#{realm.id}", :checked => selected }
+ = link_to realm.name, realm_path(realm)
diff --git a/src/app/views/realms/_section_header.haml b/src/app/views/realms/_section_header.haml
new file mode 100644
index 0000000..7230e81
--- /dev/null
+++ b/src/app/views/realms/_section_header.haml
@@ -0,0 +1,5 @@
+%header.page-header
+ %h1{:class => controller.controller_name} Realms
+ #obj_actions.button-group
+ = link_to 'New Realm', new_realm_url, :class => 'button primary', :id => 'new_realm_button'
+ .corner
diff --git a/src/app/views/realms/index.haml b/src/app/views/realms/index.haml
index acfa09b..55fac46 100644
--- a/src/app/views/realms/index.haml
+++ b/src/app/views/realms/index.haml
@@ -1,3 +1,3 @@
= render :partial => 'layouts/admin_header'
-%div#view
- = render :partial => 'list'
+= render :partial => 'section_header'
+= render :partial => 'list'
diff --git a/src/app/views/roles/_list.haml b/src/app/views/roles/_list.haml
index 5bd1247..114faa7 100644
--- a/src/app/views/roles/_list.haml
+++ b/src/app/views/roles/_list.haml
@@ -1,19 +1,24 @@
-- form_tag do
- = link_to "New Role", new_role_path, :class => 'button'
- = restful_submit_tag "Destroy", "destroy", multi_destroy_roles_path, 'DELETE', :id => 'delete_button', :class => 'button'
- %p
- Select:
- = link_to "All", @url_params.merge(:select => 'all')
- %span> ,
- = link_to "None", @url_params.merge(:select => 'none')
- %table#roles_table
- = sortable_table_header @header
- - @roles.each do |role|
- %tr
- %td
- - selected = @url_params[:select] == 'all'
- %input{:name => "role_selected[]", :type => "checkbox", :value => role.id, :id => "role_checkbox_#{role.id}", :checked => selected }
- = link_to role.name, role_path(role)
+%section.content-section.roles
+ %header
+ %h2 Roles List
+ %span.label.badge.dark.count= @roles.length
+
+ .content
+ - form_tag do
+ = restful_submit_tag "Destroy", "destroy", multi_destroy_roles_path, 'DELETE', :id => 'delete_button', :class => 'button'
+ %p
+ Select:
+ = link_to "All", @url_params.merge(:select => 'all')
+ %span> ,
+ = link_to "None", @url_params.merge(:select => 'none')
+ %table#roles_table
+ = sortable_table_header @header
+ - @roles.each do |role|
+ %tr
+ %td
+ - selected = @url_params[:select] == 'all'
+ %input{:name => "role_selected[]", :type => "checkbox", :value => role.id, :id => "role_checkbox_#{role.id}", :checked => selected }
+ = link_to role.name, role_path(role)
:javascript
$(document).ready(function () {
diff --git a/src/app/views/roles/_section_header.haml b/src/app/views/roles/_section_header.haml
new file mode 100644
index 0000000..8441d22
--- /dev/null
+++ b/src/app/views/roles/_section_header.haml
@@ -0,0 +1,5 @@
+%header.page-header
+ %h1{:class => controller.controller_name} Roles
+ #obj_actions.button-group
+ = link_to 'New Role', new_role_url, :class => 'button primary', :id => 'new_role_button'
+ .corner
diff --git a/src/app/views/roles/index.haml b/src/app/views/roles/index.haml
index acfa09b..55fac46 100644
--- a/src/app/views/roles/index.haml
+++ b/src/app/views/roles/index.haml
@@ -1,3 +1,3 @@
= render :partial => 'layouts/admin_header'
-%div#view
- = render :partial => 'list'
+= render :partial => 'section_header'
+= render :partial => 'list'
diff --git a/src/features/pool_family.feature b/src/features/pool_family.feature
index 010bac9..2954242 100644
--- a/src/features/pool_family.feature
+++ b/src/features/pool_family.feature
@@ -29,7 +29,7 @@ Feature: Pool Families
Scenario: Create a new Pool family
Given I am on the pool families page
And there is not a pool family named "testpoolfamily"
- When I follow "Create"
+ When I follow "New Pool Family"
Then I should be on the new pool family page
When I fill in "pool_family[name]" with "testpoolfamily"
When I fill in "pool_family[quota_attributes][maximum_running_instances]" with "2"
diff --git a/src/features/provider.feature b/src/features/provider.feature
index 69ac381..c49379c 100644
--- a/src/features/provider.feature
+++ b/src/features/provider.feature
@@ -50,7 +50,7 @@ Feature: Manage Providers
Scenario: Create a new Provider
Given I am on the providers page
And there is not a provider named "testprovider"
- When I follow "Create"
+ When I follow "New Provider"
Then I should be on the new provider page
When I fill in "provider[name]" with "testprovider"
And I fill in "provider[url]" with "http://localhost:3001/api"
@@ -63,7 +63,7 @@ Feature: Manage Providers
Scenario: Create a new Provider failure when using wrong url
Given I am on the providers page
And there is not a provider named "testprovider"
- When I follow "Create"
+ When I follow "New Provider"
Then I should be on the new provider page
When I fill in "provider[name]" with "testprovider"
And I fill in "provider[url]" with "http://localhost:3010/api"
diff --git a/src/features/provider_account.feature b/src/features/provider_account.feature
index d5fee06..d25ec0a 100644
--- a/src/features/provider_account.feature
+++ b/src/features/provider_account.feature
@@ -12,7 +12,7 @@ Feature: Manage Provider Accounts
Given I am on the homepage
And there is a provider named "testprovider"
When I go to the provider accounts page
- Then I should see "New Account"
+ Then I should see "New Provider Account"
And there should be no provider accounts
Scenario: List providers in XML format
@@ -32,7 +32,7 @@ Feature: Manage Provider Accounts
Given there is a provider named "testprovider"
And there are no provider accounts
And I am on the provider accounts page
- When I follow "New Account"
+ When I follow "New Provider Account"
Then I should be on the new provider account page
And I should see "New Account"
When I select "testprovider" from "provider_account_provider_id"
@@ -51,7 +51,7 @@ Feature: Manage Provider Accounts
Given there is a provider named "testprovider"
And there are no provider accounts
And I am on the provider accounts page
- When I follow "New Account"
+ When I follow "New Provider Account"
Then I should be on the new provider account page
And I should see "New Account"
When I select "testprovider" from "provider_account_provider_id"
diff --git a/src/features/realm.feature b/src/features/realm.feature
index 82deec7..5764ae0 100644
--- a/src/features/realm.feature
+++ b/src/features/realm.feature
@@ -11,7 +11,7 @@ Feature: Manage Realms
Scenario: Create new frontend realm
Given I am on the realms page
- When I follow "Create"
+ When I follow "New Realm"
Then I should see "Create a new Realm"
When I fill in "frontend_realm[name]" with "testrealm2"
And I press "Save"
--
1.7.4.2
12 years, 11 months
Trivial enhancement to new deployment UI
by Matt Wagner
This is a quick little patch to change the new deployment UI to allow selecting a realm, and to narrow the permissions that are used to be specific to the pool. It might apply cleanly on next, though I have it committed on top of sseago's patches.
-- Matt
12 years, 11 months
Fix the filter/pretty view toggle
by Tomas Sedovic
The recent changes broke switching between the filter and pretty view. This
patch makes it behave as it was before.
Note: this still doesn't take advantage of the Viewstate mechanism we've put
in earlier. I'll get to that tomorrow.
Thomas
12 years, 11 months
Image permissions, round 2
by Mark McLoughlin
(cc-ing iwhd-devel; I don't like cross-posting, but so much of this is
about IWHD, I think it's probably warranted)
Hey,
We had a follow-on discussion on the phone about image permissions where
we concentrated on the first two items:
1) Access control on IWHD objects
2) Conductor's environment based instance launch policy
The original thread is here:
https://fedorahosted.org/pipermail/aeolus-devel/2011-May/thread.html#1741
What follows is my attempt to summarize a way forward. I can't say that
it was the consensus from the discussion, but hopefully it's not too
from that.
Apologies for the length of this, but it's hard to capture the details
and still stay brief.
Cheers,
Mark.
= 1. Access Control =
There was general consensus that we need something akin to posix
filesystem permissions on IWHD objects. The use cases driving this are:
a) I build an image that contains sensitive data - e.g. private keys,
DB passwords in config files etc. - and I want to limit who can read
that data from IWHD.
b) I want to prevent others from deleting or overwriting my image data,
or even just the metadata on objects that I created.
This implies that we need read and write/delete permission on all
objects in the warehouse. Read permissions apply only the object
contents, but write permissions apply both to the contents and the
metadata.
We obviously need the concept of permissions that apply to individual
users, as well as a 'world' permission that applies to everyone. For
large organizations, group permissions will also be needed.
In order to enforce user permissions, we clearly need to authenticate
users. We probably need to support three different authentication modes:
i) For standalone usage of IWHD, a simple user/password database.
Perhaps just keep this in Mongo.
ii) When use with Conductor, IWHD should be able to authenticate using
Conductor's REST API - i.e. in IWHD config, allow an "HTTP
authentication URL" to be specified which IWHD will do Basic HTTP
authentication against.
iii) For use with Conductor where Conducor isn't using its own DB as its
user store (perhaps it is using IPA, LDAP or even just the
local /etc/passwd), IWHD should be able to authenticate using PAM.
Permissions will be represented by metadata tags on object, each of
which can either contain "rw" or "r":
user-permission:<user-id>
group-permission:<group-id>
world-permission
The aeolus-image CLI will be responsible for managing the permissions
tags:
$> aeolus-image build -t ec2 -e my.tmpl
...
Built image: 2d134860-9762-4cc3-8e63-4fab7d31ad1b
$> aeolus-image info -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b
...
user-permission-markmc: rw
...
$> aeolus-image user-permission -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b jrd rw
$> aeolus-image group-permission -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b dev rw
$> aeolus-image world-permission -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b r
$> aeolus-image user-permission -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b --delete jrd
Open questions:
- Should read permissions apply to object metadata? This probably makes
sense, but we need to think about whether we can implement that
without massively slowing down queries.
- Permissions on buckets - I don't think we need these. We are storing
all our objects in single buckets, so it's hard to see what we would
use these for. In any case, if we want to limit the ability of users
to create objects, then bucket permissions are probably the way to
go.
- Does Conductor authenticate as the Conductor user when talking to
IWHD?
- No need for a "w" permission, right? i.e. granting the permission to
write without the permission to read?
- The "rw" permission grants the user permission to delete the object.
= 2. Environment Policy =
Images are assumed to undergo a lifecycle where one version of the image
may be in production, another in staging and another in development.
These lifecycle phases are exposed to the user as environments in
Conductor. Some images may only be available in development or you may
may only have specific builds of an image available in each of the
environments.
The image administrator defines this policy - i.e. which environments
the image is allowed in, and which version of an image is appropriate
for each environment - using the aeolus-image CLI which, in turn, sets
metadata tags on IWHD objects to represent the policy.
When a user launches a deployable, or explicitly chooses an image to
launch, Conductor enforces the policy by comparing the environment the
user is launching the deployable/instance in to the the metadata tags.
The metadata tags defining this policy are place on "image" objects in
iwhd and are simply:
latest_build:<environment> = build UUID
latest_build = build UUID
The policy is enforced as follows:
- When launching a deployable in an environment, Conductor resolves an
image reference to a set of provider images by first looking at the
environment specific latest_build tag. If this doesn't exist, it
looks at the global latest_build tag. If this doesn't exist, the
deployable can't be launched
- When listing images available to be launched in a given environment,
Conductor searches for all images with either an environment
specific or global latest_build.
The image building CLI for this might look like:
$> aeolus-image build -t ec2 -e my.tmpl -i -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b
...
Rebuilding image: -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b
New build: 54848312-2d3e-405e-ac34-0c67bba22ee8
$> aeolus-image add-env -i 2d134860-9762-4cc3-8e63-4fab7d31ad1b --env prod -b 54848312-2d3e-405e-ac34-0c67bba22ee8
Set latest_build:prod = 54848312-2d3e-405e-ac34-0c67bba22ee8 on image 2d134860-9762-4cc3-8e63-4fab7d31ad1b
Note that these commands could be run by two users with different roles.
The first user may only have permission to rebuild images, whereas the
second user would be the only one that could update the latest_build tag
on the image object.
Open questions:
- There was discussion about whether the environment a user is in
should translate to access control permissions in IWHD - i.e. unless
I have been added to the development environment, not only should I
not be able to launch an instance using development images, but I
also should automatically not be able to see them using the CLI.
The implication here is that there would be a group visible to IWHD
for each environment which represents all the users added to the
environment. In the case of a shared identity store like IPA, this is
doable by having Conductor manage the group membership of the
environment groups. In the absence of a shared identity store,
perhaps we leave it up to the admin to set up these groups if they
so wish.
All that being said, I'm really struggling to convince myself that
this is terribly important. Given that so much of the discussion got
wedged on how to do this, I'd suggest punting on it for now if it's
not critical.
- The CLI commands for managing environment tags clearly require more
thought.
- If the user doesn't have write permissions to the image object, they
may be able to create a new build of the image, but they can't e.g.
update the description of the image which is stored in the image
object's body.
12 years, 11 months
1601 - iwhd models
by Tomas Hrcka
- implemented methods find(uuid), all Image, ImageBuild, ProviderImage, TargetImage
- method where for complicated queries to iwhd
- tests use dummpy data I would appreciate help with getting more real data
12 years, 11 months
[PATCH conductor] Issue #1710: update ruby console for new factory methods.
by Jason Guiditta
https://www.aeolusproject.org/redmine/issues/1710
This patch implements calls to the new methods and deprecates the old ones.
---
services/image_factory/console/Rakefile | 2 +-
.../lib/image_factory/image_factory_console.rb | 72 ++++++++++++++++++-
.../console/rubygem-image_factory_console.spec | 2 +-
.../console/spec/image_factory/console_spec.rb | 70 +++++++++++++++++++
4 files changed, 140 insertions(+), 6 deletions(-)
diff --git a/services/image_factory/console/Rakefile b/services/image_factory/console/Rakefile
index a2a925c..dcd4cc2 100644
--- a/services/image_factory/console/Rakefile
+++ b/services/image_factory/console/Rakefile
@@ -32,7 +32,7 @@ RPM_SPEC = "rubygem-image_factory_console.spec"
spec = Gem::Specification.new do |s|
s.name = 'image_factory_console'
- s.version = '0.2.0'
+ s.version = '0.3.0'
s.has_rdoc = true
#s.extra_rdoc_files = ['README', 'COPYING']
s.summary = 'QMF Console for Aeolus Image Factory'
diff --git a/services/image_factory/console/lib/image_factory/image_factory_console.rb b/services/image_factory/console/lib/image_factory/image_factory_console.rb
index c196632..01d64bd 100644
--- a/services/image_factory/console/lib/image_factory/image_factory_console.rb
+++ b/services/image_factory/console/lib/image_factory/image_factory_console.rb
@@ -54,6 +54,57 @@ class ImageFactoryConsole < Qmf2::ConsoleHandler
end
# Call this method to initiate a build, and get back an
+ # array of BuildAdaptor objects.
+ # * template => String
+ # Description of what to build. Can be xml, uuid, or url
+ # * targets => Array
+ # Represents the names of the clouds to target (ec2, mock, rackspace, etc)
+ # * image_id => String
+ # The UUID of an image previously built
+ # * build_id => String
+ # The UUID of a previous build of the image
+ # * Returns => an array of BuildAdaptor objects
+ #
+ def build(template, targets, image='', build='')
+ targets = [targets] unless targets.instance_of?(Array)
+ # TODO: return error if there is a problem calling this method or getting
+ # a factory instance
+ begin
+ response = factory.build_image(image, build, template, targets)
+ build_adaptors(response)
+ rescue Exception => e
+ @logger.debug "Encountered error in build_image: #{e}"
+ return e
+ end
+ end
+
+ # Call this method to push an image to a provider, and get back an
+ # array of BuildAdaptor objects.
+ # * providers => Array
+ # Represents the target providers to build for (ec2-us-east, mock1, etc)
+ # * credentials => String
+ # XML block to be used for registration, upload, etc
+ # * image_id => String
+ # The UUID of an image previously built
+ # * build_id => String
+ # The UUID of a previous build of the image
+ # * Returns => an array of BuildAdaptor objects
+ #
+ def push(providers, credentials, image_id, build_id='')
+ providers = [providers] unless providers.instance_of?(Array)
+ # TODO: return error if there is a problem calling this method or getting
+ # a factory instance
+ begin
+ response = factory.push_image(image_id, build_id, providers, credentials)
+ build_adaptors(response)
+ rescue Exception => e
+ @logger.debug "Encountered error in push_image: #{e}"
+ return e
+ end
+ end
+
+ # <b>DEPRECATED:</b> Please use <tt>build</tt> instead.
+ # Call this method to initiate a build, and get back an
# BuildAdaptor object.
# * descriptor => String
# This can be either xml or a url pointing to the xml
@@ -62,6 +113,7 @@ class ImageFactoryConsole < Qmf2::ConsoleHandler
# * Returns => a BuildAdaptor object
#
def build_image(descriptor, target)
+ @logger.warn "[DEPRECATION] 'build_image' is deprecated. Please use 'build' instead."
# TODO: return error if there is a problem calling this method or getting
# a factory instance
begin
@@ -73,6 +125,7 @@ class ImageFactoryConsole < Qmf2::ConsoleHandler
end
end
+ # <b>DEPRECATED:</b> Please use <tt>push</tt> instead.
# Call this method to push an image to a provider, and get back an
# BuildAdaptor object.
# * image_id => String (uuid)
@@ -83,6 +136,7 @@ class ImageFactoryConsole < Qmf2::ConsoleHandler
# * Returns => a BuildAdaptor object
#
def push_image(image_id, provider, credentials)
+ @logger.warn "[DEPRECATION] 'push_image' is deprecated. Please use 'push' instead."
# TODO: return error if there is a problem calling this method or getting
# a factory instance
begin
@@ -139,13 +193,23 @@ class ImageFactoryConsole < Qmf2::ConsoleHandler
@factory ||= @q.query("{class:ImageFactory, package:'com.redhat.imagefactory'}").first
end
+ def build_adaptors(response)
+ ret = []
+ response['build_adaptors'].each do |imgfacaddr|
+ query = Qmf2::Query.new(Qmf2::DataAddr.new(imgfacaddr))
+ ret << @q.query(query,5).first
+ end
+ ret
+ end
+
def build_adaptor(response)
+ @logger.warn "[DEPRECATION] 'build_adaptor' is deprecated. Please use 'build_adaptors' instead."
imgfacaddr = Qmf2::DataAddr.new(response['build_adaptor'])
query = Qmf2::Query.new(imgfacaddr)
@q.query(query,5).first
end
-end
-
-#i = ImageBuilderConsole.new
-#i.run
+ def make_array(a)
+ return a ||= [a] unless a.instance_of?(Array)
+ end
+end
\ No newline at end of file
diff --git a/services/image_factory/console/rubygem-image_factory_console.spec b/services/image_factory/console/rubygem-image_factory_console.spec
index 1a54dfd..f3046fa 100644
--- a/services/image_factory/console/rubygem-image_factory_console.spec
+++ b/services/image_factory/console/rubygem-image_factory_console.spec
@@ -6,7 +6,7 @@
Summary: QMF Console for Aeolus Image Factory
Name: rubygem-%{gemname}
-Version: 0.2.0
+Version: 0.3.0
Release: 1%{?dist}%{?extra_release}
Group: Development/Languages
License: GPLv2+ or Ruby
diff --git a/services/image_factory/console/spec/image_factory/console_spec.rb b/services/image_factory/console/spec/image_factory/console_spec.rb
index 9cd766d..41a6ed1 100644
--- a/services/image_factory/console/spec/image_factory/console_spec.rb
+++ b/services/image_factory/console/spec/image_factory/console_spec.rb
@@ -14,6 +14,12 @@ module ImageFactory
# We might be able to extract this somewhere to hold off
# on tests until we get an agent_added notification
sleep(5)
+ #TODO: take this snippet and make a fixture of some sort to use in tests
+ #tmpl = '<template> <name>tmpl1</name> <description>foo</description> <os> <name>Fedora</name>
+ # <arch>x86_64</arch> <version>14</version> <install type="url">
+ # <url>http://download.fedoraproject.org/pub/fedora/linux/releases/14/Fedora/x86...</url> </install>
+ # </os> <repositories> <repository name="custom"> <url>http://repos.fedorapeople.org/repos/aeolus/demo/webapp/</url>
+ # <signed>false</signed> </repository> </repositories> </template>'
end
describe "#q" do
@@ -37,6 +43,50 @@ module ImageFactory
end
end
+ describe "#build" do
+ it "should return an array of build-adaptors with uuids" do
+ @i.build("<template></template>", ["mock"]).each do |adaptor|
+ adaptor.image_id.should_not be_nil
+ adaptor.image.should_not be_nil
+ adaptor.build.should_not be_nil
+ end
+ end
+
+ it "should work with single target as string" do
+ @i.build("<template></template>", "mock").each do |adaptor|
+ adaptor.image_id.should_not be_nil
+ adaptor.image.should_not be_nil
+ adaptor.build.should_not be_nil
+ end
+ end
+ end
+
+ describe "#push" do
+ it "should return an array of build-adaptors with uuids" do
+ @i.build("<template></template>", ["mock"]).each do |adaptor|
+ #(a)i.handler = BaseHandler.new(@logger)
+ @i.handler.should_not_receive(:handle_failed)
+ @i.push(["mock"], "<provider_credentials/>", adaptor.image).each do |a|
+ a.image_id.should_not be_nil
+ a.image.should_not be_nil
+ a.build.should_not be_nil
+ end
+ end
+ end
+
+ it "should work with single provider as string" do
+ @i.build("<template></template>", "mock").each do |adaptor|
+ #(a)i.handler = BaseHandler.new(@logger)
+ @i.handler.should_not_receive(:handle_failed)
+ @i.push("mock1", "<provider_credentials/>", adaptor.image).each do |a|
+ a.image_id.should_not be_nil
+ a.image.should_not be_nil
+ a.build.should_not be_nil
+ end
+ end
+ end
+ end
+
after(:all) do
@i.shutdown
end
@@ -108,6 +158,7 @@ module ImageFactory
describe "#build_image" do
it "should gracefully handle errors" do
@output.should_receive(:debug).with(/Encountered error in build_image/)
+ @output.should_receive(:warn).with("[DEPRECATION] 'build_image' is deprecated. Please use 'build' instead.")
@i2.q=nil
error = @i2.build_image("<template></template>", "mock")
error.to_s.should include("undefined method")
@@ -117,12 +168,31 @@ module ImageFactory
describe "#push_image" do
it "should gracefully handle errors" do
@output.should_receive(:debug).with(/Encountered error in push_image/)
+ @output.should_receive(:warn).with("[DEPRECATION] 'push_image' is deprecated. Please use 'push' instead.")
@i2.q=nil
error = @i2.push_image(123, "mock", "some creds")
error.to_s.should include("undefined method")
end
end
+ describe "#build" do
+ it "should gracefully handle errors" do
+ @output.should_receive(:debug).with(/Encountered error in build_image/)
+ @i2.q=nil
+ error = @i2.build("<template></template>", "mock")
+ error.to_s.should include("undefined method")
+ end
+ end
+
+ describe "#push" do
+ it "should gracefully handle errors" do
+ @output.should_receive(:debug).with(/Encountered error in push_image/)
+ @i2.q=nil
+ error = @i2.push(123, "mock", "some creds")
+ error.to_s.should include("undefined method")
+ end
+ end
+
after(:each) do
@output.should_receive(:debug).with(/Closing/)
@i2.shutdown
--
1.7.4.4
12 years, 11 months
ANNOUNCE: oz 0.4.0 release
by Chris Lalancette
All,
I'm pleased to announce release 0.4.0 of Oz. Oz is a program for doing
automated installation of guest operating systems with limited input from the
user.
Release 0.4.0 is a bugfix and feature release for Oz. Some of the
highlights between Oz 0.3.0 and 0.4.0 are:
- Automatic detection/use of cached JEOS images (the previous method required
the user of the oz libraries to detect whether the image was cached or not)
- Fixes to make Debian installs work for both x86_64 and i386
- Honor user-provided automatic installation files better, by not doing
modifications
- Use pyparted to generate partitions on newly created disks (if necessary)
- Add support for Fedora 15
- Add the ability to supply an initial root/Administrator password to the
diskimage
- Abort installs after 5 minutes of disk inactivity
- Use M2Crypto to generate SSH keys (if necessary)
- Some pydoc documentation (more of this to come in the future)
- Support for Ubuntu 11.04
- Support for RHEL-6.1
More documentation on Oz (including links on how to obtain it) is available
here: http://aeolusproject.org/oz.html
For this release, Fedora 14 and RHEL-6 packages are available. Note that I
have stopped providing Fedora 13 packages, since that distribution is (or
will be) out of support. Also note that to install the RHEL-6
packages, you must be running RHEL-6.1 or later.
If you have any questions or comments about Oz, please feel free to contact
aeolus-devel(a)lists.fedorahosted.org or me (clalance(a)redhat.com) directly.
Thanks,
--
Chris Lalancette
12 years, 11 months