[PATCH conductor] Add Build & Push to Deployable Details

Jan Provazník jprovazn at redhat.com
Fri Dec 2 16:36:54 UTC 2011


On 12/02/2011 04:13 PM, tsedovic at redhat.com wrote:
> From: Tomas Sedovic<tomas at sedovic.cz>
>
> https://www.aeolusproject.org/redmine/issues/2853
>
> It shows the following states: not built, building, not pushed, pushing,
> pushed. And it allows the user to rebuild and re-push all images.
>
> As things are now, building and pushing is a 2-step operation.
>
> Note that the page isn't styled properly yet.
> ---
>   src/app/controllers/deployables_controller.rb |   33 ++++++++++++
>   src/app/models/deployable.rb                  |   70 ++++++++++++++++++++++---
>   src/app/views/deployables/show.html.haml      |   35 ++++++++-----
>   src/config/locales/en.yml                     |    9 +++
>   src/config/routes.rb                          |    1 +
>   5 files changed, 127 insertions(+), 21 deletions(-)
>
> diff --git a/src/app/controllers/deployables_controller.rb b/src/app/controllers/deployables_controller.rb
> index a1d7f9b..a6457d3 100644
> --- a/src/app/controllers/deployables_controller.rb
> +++ b/src/app/controllers/deployables_controller.rb
> @@ -64,6 +64,21 @@ class DeployablesController<  ApplicationController
>           flash[:error] = assembly[key] if key.to_s =~ /^error\w+/
>         end
>       end
> +    images = @deployable.fetch_images
> +    uuids = @deployable.fetch_image_uuids
> +    @missing_images = images.zip(uuids).select{|p| p.first.nil?}.map{|p| p.second}
> +    return unless @missing_images.empty?
> +
> +    @build_results = {}
> +    ProviderAccount.list_for_user(current_user, Privilege::VIEW).each do |account|
> +      type = account.provider.provider_type.deltacloud_driver
> +      @build_results[type] ||= []
> +      @build_results[type]<<  {
> +        :account =>  account.label,
> +        :provider =>  account.provider.name,
> +        :status =>  @deployable.build_status(images, account),
> +      }
> +    end
>     end
>
>     def create
> @@ -171,6 +186,24 @@ class DeployablesController<  ApplicationController
>       redirect_to original_path.merge(original_params).merge("catalog_entries_preset_filter" =>  params[:catalog_entries_preset_filter], "catalog_entries_search" =>  params[:catalog_entries_search])
>     end
>
> +  def build
> +    catalog = Catalog.find(params[:catalog_id])
> +    deployable = Deployable.find(params[:deployable_id])
> +    require_privilege(Privilege::MODIFY, catalog)
> +    require_privilege(Privilege::MODIFY, deployable)
> +
> +    images = deployable.fetch_images
> +    accounts = ProviderAccount.list_for_user(current_user, Privilege::VIEW)
> +    options = params[:build_options].to_sym
> +    case options
> +    when :build_missing
> +      deployable.build_missing(images, accounts)
> +    when :push_missing
> +      deployable.push_missing(images, accounts)
> +    end
> +    redirect_to catalog_deployable_path(catalog, deployable)
> +  end
> +
>     private
>
>     def set_header
> diff --git a/src/app/models/deployable.rb b/src/app/models/deployable.rb
> index 2a568ac..ac68454 100644
> --- a/src/app/models/deployable.rb
> +++ b/src/app/models/deployable.rb
> @@ -60,13 +60,8 @@ class Deployable<  ActiveRecord::Base
>
>     # Round up Catalog Entries, fetch their Deployables, and extract image UUIDs.
>     def fetch_images
> -    images = []
> -    unless fetch_image_uuids.nil?
> -      fetch_image_uuids.each do |uuid|
> -        images<<  Aeolus::Image::Warehouse::Image.find(uuid)
> -      end
> -      return images.compact.uniq
> -    end
> +    uuids = fetch_image_uuids || []
> +    uuids.map { |uuid| Aeolus::Image::Warehouse::Image.find(uuid) }
>     end

^ since this method now returns nil values too, handle nil value where 
it's called from:
app/models/pool.rb
app/views/deployments/launch_from_catalog.html.haml

>
>     def fetch_image_uuids
> @@ -143,6 +138,66 @@ class Deployable<  ActiveRecord::Base
>       result_array
>     end
>
> +  def build_status(images, account)
> +    image_statuses = images.map { |i| image_status(i, account) }
> +    return :not_built if image_statuses.any? { |status| status == :not_built }
> +    return :building if image_statuses.any? { |status| status == :building }
> +    return :pushing if image_statuses.any? { |status| status == :pushing }
> +    return :not_pushed if image_statuses.any? { |status| status == :not_pushed }
> +    :pushed
> +  end
> +
> +  def image_status(image, account)
> +    build = image.latest_pushed_or_unpushed_build
> +    target = account.provider.provider_type.deltacloud_driver
> +    return :not_built unless build
> +
> +    builder = Aeolus::Image::Factory::Builder.first
> +    return :building if builder.find_active_build(build.id, target)
> +
> +    target_image = build.target_images.find { |ti| ti.target == target }
> +    return :not_built unless target_image
> +
> +    return :pushing if builder.find_active_push(target_image.id,
> +                                                account.provider.name,
> +                                                account.credentials_hash["username"])
> +
> +    provider_image = target_image.find_provider_image_by_provider_and_account(
> +        account.provider.name, account.warehouse_id).first
> +    return :not_pushed unless provider_image
> +    :pushed
> +  end
> +
> +  def build_missing(images, accounts)
> +    targets = accounts.map { |acc| acc.provider.provider_type.deltacloud_driver }.uniq.join(',')
> +    images.each do |image|
> +      factory_image = Aeolus::Image::Factory::Image.new(:id =>  image.id)
> +      factory_image.targets = targets
> +      factory_image.template = image.template
> +      factory_image.save!
> +    end
> +  end
> +
> +  def push_missing(images, accounts)
> +    images.each do |image|
> +      accounts.each do |account|
> +        if image_status(image, account) == :not_pushed
> +          target = account.provider.provider_type.deltacloud_driver
> +          build = image.latest_pushed_or_unpushed_build
> +          target_image = build.target_images.find { |ti| ti.target == target }
> +          provider_image = Aeolus::Image::Factory::ProviderImage.new(
> +            :provider =>  account.provider.name,
> +            :credentials =>  account.to_xml(:with_credentials =>  true),
> +            :image_id =>  image.uuid,
> +            :build_id =>  build.uuid,
> +            :target_image_id =>  target_image.uuid
> +          )
> +          provider_image.save!
> +        end
> +      end
> +    end
> +  end
> +
>     private
>
>     def self.apply_search_filter(search)
> @@ -152,5 +207,4 @@ class Deployable<  ActiveRecord::Base
>         scoped
>       end
>     end
> -
>   end
> diff --git a/src/app/views/deployables/show.html.haml b/src/app/views/deployables/show.html.haml
> index e09f4bf..6a8576a 100644
> --- a/src/app/views/deployables/show.html.haml
> +++ b/src/app/views/deployables/show.html.haml
> @@ -39,19 +39,28 @@
>       %header
>         %h2= t('.build')
>
> -      = form_tag() do
> -        = select_tag :build_option, options_for_select([[t("rebuild_all"), 1]])
> -        = submit_tag t('.start'), :id =>  :start_build
> +      - if @missing_images.empty?
> +        = form_tag(catalog_deployable_build_path(@catalog, @deployable)) do
> +          = select_tag :build_options, options_for_select([[t(".build_missing"), :build_missing], [t(".push_missing"), :push_missing]])
> +          = submit_tag t('.start'), :id =>  :start_build
>
> -      %p.description= t('.build_description')
> +        %p.description= t('.build_description')
>
> -      %ul#providers-list
> -        - @providers.each do |provider|
> -          %li
> -            %span.provider= provider.name
> -            %span.status Building 98%
> -            -#= form_tag()
> -            -#  %button on/off
> +        %ul#providers-list
> +          - @build_results.each do |provider_type, results|
> +            %li
> +              = provider_type
> +              %ul
> +                - results.each do |result|
> +                  %li
> +                    %span.provider= result[:provider]
> +                    %span.account= result[:account]
> +                    %span.status= result[:status]
> +      - else
> +        %h3= t('.missing_images')
> +        %ul#missing-images-list
> +          - @missing_images.each do |uuid|
> +            %li= uuid
>
>
>     %section.catalogs
> diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml
> index e45d743..2819ce6 100644
> --- a/src/config/locales/en.yml
> +++ b/src/config/locales/en.yml
> @@ -783,6 +783,15 @@ en:
>         not_deleted:
>           one: "Deployable %{list} was not deleted. There are deployments associated with it."
>           other: "Deployables %{list} were not deleted. They have deployments associated with them."
> +    show:
> +      build: Build
> +      build_description:
> +        "Allow this deployable's associated image(s) to be built and pushed to
> +        providers by enabling them below."
> +      start: Start
> +      rebuild_all: Build missing images
> +      push_all: Push missing images
> +      missing_images: Images missing from the Image Warehouse
>       flash:
>         error:
>           attribute_not_exist: "Some attribute(s) is missing in XML, please check the file!"
> diff --git a/src/config/routes.rb b/src/config/routes.rb
> index 7a7df6e..b07ba9e 100644
> --- a/src/config/routes.rb
> +++ b/src/config/routes.rb
> @@ -205,6 +205,7 @@ Conductor::Application.routes.draw do
>       resources :deployables do
>         delete 'multi_destroy', :on =>  :collection
>         post :filter, :on =>  :collection
> +      post :build
>       end
>     end
>

Hi Tomas,
code looks good, works for me. Conditional ACK - see inline note.

As we discussed on IRC: optional build_id param in deployable XML is 
ignored for now, will be fixed later.

Great work, Jan



More information about the aeolus-devel mailing list