On 11/29/2011 11:13 AM, jprovazn(a)redhat.com wrote:
> From: Jan Provaznik<jprovazn(a)redhat.com>
>
> - you need to build newest imagefactory and apply patch which extends
> builder:
> git pull
https://github.com/aeolusproject/imagefactory feature/rm2859
> - upload/build is allowed only for latest builds
> - target image is not displayed if there is not an account for this
> type of provider
> ---
> src/app/controllers/images_controller.rb | 44 +++++++--
> src/app/controllers/provider_images_controller.rb | 19 +---
> src/app/controllers/target_images_controller.rb | 54 +++++++++++
> src/app/helpers/images_helper.rb | 30 ++++++
> src/app/models/provider_account.rb | 21 +++++
> src/app/models/provider_type.rb | 5 -
> src/app/stylesheets/layout.scss | 37 ++++++++
> src/app/views/images/show.html.haml | 100 +++++++++++++-------
> src/config/locales/en.yml | 20 ++++-
> src/config/routes.rb | 7 +-
> 10 files changed, 270 insertions(+), 67 deletions(-)
> create mode 100644 src/app/controllers/target_images_controller.rb
> create mode 100644 src/app/helpers/images_helper.rb
>
> diff --git a/src/app/controllers/images_controller.rb
> b/src/app/controllers/images_controller.rb
> index 514e842..4859a6a 100644
> --- a/src/app/controllers/images_controller.rb
> +++ b/src/app/controllers/images_controller.rb
> @@ -37,15 +37,22 @@ class ImagesController< ApplicationController
>
> def show
> @image = Aeolus::Image::Warehouse::Image.find(params[:id])
> - @builds = @image.image_builds
> - @build = if params[:build].present?
> - @builds.find {|b| b.id == params[:build]}
> - elsif @image.respond_to?(:latest_build) and @image.latest_build
> - @builds.find {|b| b.id == @image.latest_build}
> - else
> - @builds.first
> - end
> - @provider_types = ProviderType.all
> + @account_groups = ProviderAccount.group_by_type(current_user)
> + # according to imagefactory Builder.first shouldn't be implemented yet
> + # but it does what we need - returns builder object which contains
> + # all builds
> + @builder = Aeolus::Image::Factory::Builder.first
> + load_builds
> + load_target_images(@build)
> + end
> +
> + def rebuild_all
> + @image = Aeolus::Image::Warehouse::Image.find(params[:id])
> + factory_image = Aeolus::Image::Factory::Image.new(:id => @image.id)
> + factory_image.targets = Provider.list_for_user(current_user,
> Privilege::VIEW).map {|p|
> p.provider_type.deltacloud_driver}.uniq.join(',')
> + factory_image.template = @image.template_xml.to_s
> + factory_image.save!
> + redirect_to image_path((a)image.id)
> end
>
> def new
> @@ -203,4 +210,23 @@ class ImagesController< ApplicationController
>
> doc.xpath('/template/name').first.content = name unless name.blank?
> end
> +
> + def load_target_images(build)
> + @target_images_by_target = {}
> + return unless build
> + build.target_images.each {|timg|
> @target_images_by_target[timg.target] = timg}
> + @target_images_by_target
> + end
> +
> + def load_builds
> + @builds = @image.image_builds.sort {|a, b| a.timestamp<=>
> b.timestamp}.reverse
> + @latest_build = @image.latest_pushed_or_unpushed_build.uuid rescue nil
> + @build = if params[:build].present?
> + @builds.find {|b| b.id == params[:build]}
> + elsif @latest_build
> + @builds.find {|b| b.id == @latest_build}
> + else
> + @builds.first
> + end
> + end
> end
> diff --git a/src/app/controllers/provider_images_controller.rb
> b/src/app/controllers/provider_images_controller.rb
> index 94b9df5..0839f09 100644
> --- a/src/app/controllers/provider_images_controller.rb
> +++ b/src/app/controllers/provider_images_controller.rb
> @@ -19,18 +19,6 @@
> class ProviderImagesController< ApplicationController
> before_filter :require_user
>
> - def index
> - end
> -
> - def show
> - end
> -
> - def edit
> - end
> -
> - def update
> - end
> -
> def create
> provider_account = ProviderAccount.find(params[:account_id])
> @provider_image = Aeolus::Image::Factory::ProviderImage.new(
> @@ -38,14 +26,14 @@ class ProviderImagesController< ApplicationController
> :credentials => provider_account.to_xml(:with_credentials => true),
> :image_id => params[:image_id],
> :build_id => params[:build_id],
> - :target_image_id => params[:target_image_is]
> + :target_image_id => params[:target_image_id]
> )
> if @provider_image.save
> flash[:notice] = t('provider_images.flash.notice.upload_start')
> else
> flash[:warning] = t('provider_images.flash.warning.upload_failed')
> end
> - redirect_to image_path(params[:image_id])
> + redirect_to image_path(params[:image_id], :build => params[:build_id])
> end
>
> def destroy
> @@ -61,6 +49,7 @@ class ProviderImagesController< ApplicationController
> else
> flash[:warning] = t('provider_images.flash.warning.not_found')
> end
> - redirect_to image_path(params[:image_id])
> + build_id = image.build.id rescue nil
> + redirect_to image_path(params[:image_id], :build => build_id)
> end
> end
> diff --git a/src/app/controllers/target_images_controller.rb
> b/src/app/controllers/target_images_controller.rb
> new file mode 100644
> index 0000000..a2cdd3e
> --- /dev/null
> +++ b/src/app/controllers/target_images_controller.rb
> @@ -0,0 +1,54 @@
> +#
> +# Copyright (C) 2011 Red Hat, Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; version 2 of the License.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> +# MA 02110-1301, USA. A copy of the GNU General Public License is
> +# also available at
http://www.gnu.org/copyleft/gpl.html.
> +
> +class TargetImagesController< ApplicationController
> + before_filter :require_user
> +
> + def create
> + wh_image = Aeolus::Image::Warehouse::Image.find(params[:image_id])
> +
> + begin
> + timage = Aeolus::Image::Factory::Image.new(
> + :id => params[:image_id],
> + :template => wh_image.template_xml.to_s,
> + :build_id => params[:build_id],
> + :targets => params[:target]
> + )
> + timage.save!
> + rescue
> + logger.error $!.message
> + logger.error $!.backtrace.join("\n ")
> + flash[:warning] = $!.message
> + end
> + redirect_to image_path(params[:image_id], :build => params[:build_id])
> + end
> +
> + def destroy
> + if image = Aeolus::Image::Warehouse::TargetImage.find(params[:id])
> + if image.delete!
> + flash[:notice] = t('target_images.flash.notice.deleted')
> + else
> + flash[:warning] = t('target_images.flash.warning.delete_failed')
> + end
> + else
> + flash[:warning] = t('target_images.flash.warning.not_found')
> + end
> + build_id = image.build.id rescue nil
> + redirect_to image_path(params[:image_id], :build => build_id)
> + end
> +end
> diff --git a/src/app/helpers/images_helper.rb
> b/src/app/helpers/images_helper.rb
> new file mode 100644
> index 0000000..dd1d22e
> --- /dev/null
> +++ b/src/app/helpers/images_helper.rb
> @@ -0,0 +1,30 @@
> +#
> +# Copyright (C) 2011 Red Hat, Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; version 2 of the License.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> +# MA 02110-1301, USA. A copy of the GNU General Public License is
> +# also available at
http://www.gnu.org/copyleft/gpl.html.
> +
> +# Filters added to this controller apply to all controllers in the
> application.
> +# Likewise, all the methods added will be available for all controllers.
> +
> +module ImagesHelper
> + def options_for_build_select(builds, selected, latest)
> + options_for_select(builds.map do |b|
> + label = Time.at(b.timestamp.to_f).to_s
> + label += " (#{t'images.show.latest'})" if b.uuid == latest
> + [label, b.uuid]
> + end, selected ? selected.uuid : nil)
> + end
> +end
> diff --git a/src/app/models/provider_account.rb
> b/src/app/models/provider_account.rb
> index bdb3100..4fadf6e 100644
> --- a/src/app/models/provider_account.rb
> +++ b/src/app/models/provider_account.rb
> @@ -302,4 +302,25 @@ class ProviderAccount< ActiveRecord::Base
> end
> doc.to_xml
> end
> +
> + def self.group_by_type(user)
> + res = {}
> + ProviderAccount.list_for_user(user, Privilege::VIEW).each do |account|
> + ptype = account.provider.provider_type
> + res[ptype.deltacloud_driver] ||= {:type => ptype, :accounts => []}
> + res[ptype.deltacloud_driver][:accounts]<< account
> + end
> + res
> + end
> +
> + def warehouse_id
> + # TODO: provider_account_identifier is not set for 'mock' provider
> images
> + # in warehouse, provider_image is supposed to be pushed to all mock
> provider
> + # accounts then
> + if provider.provider_type.deltacloud_driver == 'mock'
> + return nil
> + else
> + return credentials_hash['username']
> + end
> + end
> end
> diff --git a/src/app/models/provider_type.rb
> b/src/app/models/provider_type.rb
> index 2d59f47..33b1a2e 100644
> --- a/src/app/models/provider_type.rb
> +++ b/src/app/models/provider_type.rb
> @@ -39,9 +39,4 @@ class ProviderType< ActiveRecord::Base
> validates_uniqueness_of :name
> validates_presence_of :deltacloud_driver
> validates_uniqueness_of :deltacloud_driver
> -
> - def provider_accounts_for_user(user)
> - providers = Provider.list_for_user(user,
> Privilege::VIEW).where(:provider_type_id => self.id)
> - providers.inject([]) {|all, p| all +=
> ProviderAccount.list_for_user(user,
> Privilege::VIEW).where(:provider_id => p.id)}
> - end
> end
> diff --git a/src/app/stylesheets/layout.scss
> b/src/app/stylesheets/layout.scss
> index a0733e5..8d60317 100644
> --- a/src/app/stylesheets/layout.scss
> +++ b/src/app/stylesheets/layout.scss
> @@ -2260,6 +2260,7 @@ ul.deployment-array.small +
> ul.deployment-array.small{
> margin-top: 10px;
> }
>
> +
> /**************************************************************************
> */
> /********************************************* Instances Card Array */
> /**************************************************************************
> */
> @@ -2486,6 +2487,42 @@ ul.catalog_pretty {
> }
> }
>
> +/**************************************************************************
> */
> +/********************************************* Image show view */
> +/**************************************************************************
> */
> +
> +.image_builds h1 {
> + padding: 10px;
> + font-size: 16px;
> +}
> +
> +dl.image_builds {
> + border: 1px solid #ccc;
> + -webkit-border-radius: 7px 7px 7px 7px; -moz-border-radius: 7px 7px
> 7px 7px; border-radius: 7px 7px 7px 7px;
> + margin: 10px 0px 10px 0px;
> + background: #eee;
> + dt{
> + padding: 20px;
> + float:left;
> + text-align: center;
> + width:150px;
> + border-right: solid #ccc 1px;
> + border-top: 1px solid #ccc;
> + }
> + dd{
> + margin-left: 180px;
> + border-top: 1px solid #ccc;
> + table{
> + margin: 10px 10px 10px 42px;
> + td,th{ padding: 10px; width: 150px;}
> + td:first-child, th:first-child{padding-left: 0px;}
> + td:last-child, th:last-child{padding-right: 0px;}
> + th{border-bottom: 1px solid #CCCCCC;font-weight: bold;}
> + }
> + }
> +}
> +
> +
> /*
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Flat Table Component -- v.0.0.1 [flat_table] (flat_table.scss)
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> */
> diff --git a/src/app/views/images/show.html.haml
> b/src/app/views/images/show.html.haml
> index fdb77f0..6409546 100644
> --- a/src/app/views/images/show.html.haml
> +++ b/src/app/views/images/show.html.haml
> @@ -6,39 +6,69 @@
> = link_to t('images.index.images'), images_path
> .button-group
> = button_to t("delete"), image_path((a)image.id), :method =>
'delete',
> :confirm => "Are you sure you want to delete?", :class =>
'button
> danger', :id => 'delete'
> + = link_to t('.new_blueprint_from_image'),
> new_catalog_entry_path(:create_from_image => @image.id)
>
> -- unless @build
> - = t('images.show.build_not_found')
> --else
> - %section.admin-content-section
> - %header
> - %h2
> - = t('images.show.provider_images')
> - .content
> - %ul
> - - @build.target_images.each do |target_image|
> - - type = @provider_types.find {|pt| pt.deltacloud_driver ==
> target_image.target}
> - %ul
> - = type.name
> - / TODO: what if an account is renamed in condutor?
> - - all_accounts = type.provider_accounts_for_user(current_user)
> - - target_image.provider_images.each do |provider_image|
> - %li
> - = form_tag provider_image_path(provider_image.id), :method =>
> :delete do
> - - all_accounts.delete_if {|a| a.name == provider_image.provider}
> - = hidden_field_tag 'image_id', @image.id
> - = "#{t('images.show.provider_account')}:
#{provider_image.provider}"
> - %br
> - = "#{t('images.show.image_uuid')}: #{provider_image.id}"
> - %br
> - = submit_tag t('delete'), :class => 'button danger'
> - - all_accounts.each do |account|
> - %li
> - = form_tag provider_images_path do
> - = hidden_field_tag 'account_id', account.id
> - = hidden_field_tag 'image_id', @image.id
> - = hidden_field_tag 'build_id', @build.id
> - = hidden_field_tag 'target_image_id', target_image.id
> - = "#{t('images.show.provider_account')}: #{account.name}"
> - %br
> - = submit_tag t('images.show.upload')
> +%section.admin-content-section
> + %header
> + %h2
> + = t('.provider_images')
> + = t'.view_build'
> + = form_tag image_path((a)image.id), :method => :get do
> + = select_tag :build, options_for_build_select(@builds, @build,
> @latest_build)
> + = submit_tag t('.select_build'), :id => 'seletect_build_button'
> + = button_to t('.rebuild_all'), rebuild_all_image_path((a)image.id)
> + .content
> + %dl.image_builds
> + - @account_groups.each do |driver, group|
> + - timg = @target_images_by_target[driver]
> + %dt
> + %h1
> + = group[:type].name
> + - if @build and b = @builder.find_active_build((a)build.id, driver)
> + = label_tag b.status
> + - elsif timg
> + = button_to t('.delete'), image_target_image_path((a)image.id,
> timg.id), :method => :delete
> + - elsif @build and @build.id == @latest_build
> + = button_to t('.build'), image_target_images_path((a)image.id, :target
> => driver, :build_id => @build ? @build.id : nil), :method => :post
> + - else
> +
> + %dd
> + %div
> + %table
> + %thead
> + %th
> + = t'.account'
> + %th
> + = t'.provider'
> + %th
> + = t'.image_uri'
> + %th
> +
> + %tbody
> + - group[:accounts].each do |account|
> + - pimg = timg ?
> timg.find_provider_image_by_provider_and_account(account.provider.name,
account.warehouse_id).first
> : nil
> + %tr
> + %td
> + = account.name
> + %td
> + = account.provider.name
> + %td
> + = pimg ? pimg.target_identifier : '-'
> + %td
> + - if timg and b = @builder.find_active_push(timg.id,
> account.provider.name, account.warehouse_id)
> + = label_tag b.status
> + - elsif timg and not pimg and @build and @build.id == @latest_build
> + = button_to t('.upload'), image_provider_images_path((a)image.id,
> :build_id => @build.id, :target_image_id => timg.id, :account_id =>
> account.id), :method => :post
> + - elsif pimg
> + = button_to t('delete'), image_provider_image_path((a)image.id,
> pimg.id), :method => :delete
> + - else
> +
> + .clear
> +
> +:javascript
> + $(document).ready(function(){
> + $("#seletect_build_button").hide();
> + $("#build").change(function() {
> + $("#seletect_build_button").click();
> + });
> + });
> diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml
> index bb38138..7200b78 100644
> --- a/src/config/locales/en.yml
> +++ b/src/config/locales/en.yml
> @@ -644,6 +644,13 @@ en:
> preset_filters:
> all_catalogs: "All Catalogs"
> belongs_to_default_pool: "Belongs to Default Pool"
> + target_images:
> + flash:
> + notice:
> + deleted: Target Image Deleted
> + warning:
> + delete_failed: Unable to Delete Target Image
> + not_found: Target Image not found
> images:
> environment: %{environment} Environment
> import:
> @@ -661,11 +668,22 @@ en:
> os_version: OS Version
> architecture: Architecture
> show:
> - provider_images: Provider Images
> + provider_images: Cloud Resource Provider Images
> provider_account: Provider Account
> image_uuid: Image UUID
> upload: Upload
> build_not_found: "Build not found"
> + new_blueprint_from_image: "New App Blueprint from Image"
> + view_build: View build
> + rebuild_all: Rebuild All
> + build: Build
> + delete: Delete
> + account: Account
> + image_uri: Image URI
> + provider: Provider
> + build_date: Build Completion Date
> + latest: Latest
> + select_build: Select
> flash:
> notice:
> deleted: Image Deleted
> diff --git a/src/config/routes.rb b/src/config/routes.rb
> index 838e1c0..b3eae45 100644
> --- a/src/config/routes.rb
> +++ b/src/config/routes.rb
> @@ -201,16 +201,19 @@ Conductor::Application.routes.draw do
> resources :catalog_entries
>
> resources :images do
> + member do
> + post 'rebuild_all'
> + end
> collection do
> post 'edit_xml'
> post 'overview'
> delete 'multi_destroy'
> post 'import'
> end
> + resources :target_images
> + resources :provider_images
> end
>
> - resources :provider_images
> -
> get 'api', :controller => 'api/entrypoint', :action =>
'index'
> namespace :api do
> resources :images do
ACK to all.
Note that we're still using the "old" names for Aeolus. The recently
proposed name changes will not get into the upstream 1.0.
Names updated to 'old' naming and pushed. Thanks for the review.
Jan