|
#
|
|
# Copyright 2014 Red Hat, Inc.
|
|
#
|
|
# This software is licensed to you under the GNU General Public
|
|
# License as published by the Free Software Foundation; either version
|
|
# 2 of the License (GPLv2) or (at your option) any later version.
|
|
# There is NO WARRANTY for this software, express or implied,
|
|
# including the implied warranties of MERCHANTABILITY,
|
|
# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
|
|
# have received a copy of GPLv2 along with this software; if not, see
|
|
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
|
|
|
module Katello
|
|
class Api::V2::SubscriptionsController < Api::V2::ApiController
|
|
include ConsumersControllerLogic
|
|
|
|
before_filter :find_activation_key
|
|
before_filter :find_system
|
|
before_filter :find_optional_organization, :only => [:index, :available]
|
|
before_filter :find_organization, :only => [:upload, :delete_manifest, :refresh_manifest]
|
|
before_filter :find_subscription, :only => [:show]
|
|
before_filter :find_provider
|
|
before_filter :authorize
|
|
|
|
before_filter :load_search_service, :only => [:index, :available]
|
|
|
|
resource_description do
|
|
description "Subscriptions management."
|
|
api_version 'v2'
|
|
end
|
|
|
|
def rules
|
|
read_test = lambda do
|
|
return @system.readable? if @system
|
|
return ActivationKey.readable(@activation_key.organization) if @activation_key
|
|
@provider.readable?
|
|
end
|
|
available_test = lambda { Organization.any_readable? }
|
|
modification_test = lambda do
|
|
return @system.editable? if @system
|
|
return ActivationKey.manageable?(@activation_key.organization) if @activation_key
|
|
return @distributor.editable? if @distributor
|
|
@provider.editable?
|
|
end
|
|
edit_test = lambda { @provider.editable? }
|
|
|
|
{
|
|
:index => read_test,
|
|
:show => read_test,
|
|
:create => modification_test,
|
|
:destroy => modification_test,
|
|
:destroy_all => modification_test,
|
|
:available => available_test,
|
|
:upload => edit_test,
|
|
:delete_manifest => edit_test,
|
|
:refresh_manifest => edit_test
|
|
}
|
|
end
|
|
|
|
api :GET, "/systems/:system_id/subscriptions", "List a system's subscriptions"
|
|
api :GET, "/organizations/:organization_id/subscriptions", "List organization subscriptions"
|
|
api :GET, "/activation_keys/:activation_key_id/subscriptions", "List an activation key's subscriptions"
|
|
param :system_id, String, :desc => "UUID of the system", :required => false
|
|
param :activation_key_id, String, :desc => "Activation key ID", :required => false
|
|
param :organization_id, :identifier, :desc => "Organization ID", :required => false
|
|
def index
|
|
subscriptions = if @system
|
|
index_system
|
|
elsif @activation_key
|
|
index_activation_key
|
|
else
|
|
index_organization
|
|
end
|
|
|
|
respond_for_index(:collection => subscriptions)
|
|
end
|
|
|
|
api :GET, "/organizations/:organization_id/subscriptions/:id", "Show a subscription"
|
|
api :GET, "/subscriptions/:id", "Show a subscription"
|
|
param :organization_id, :number, :desc => "Organization identifier"
|
|
param :id, :number, :desc => "Subscription identifier", :required => true
|
|
def show
|
|
respond :resource => @subscription
|
|
end
|
|
|
|
def available
|
|
subscriptions = if @system
|
|
available_system
|
|
elsif @activation_key
|
|
available_activation_key
|
|
else
|
|
available_organization
|
|
end
|
|
|
|
respond_for_index(:collection => subscriptions, :template => 'index')
|
|
end
|
|
|
|
api :POST, "/subscriptions/:id", "Add a subscription to a resource"
|
|
api :POST, "/systems/:system_id/subscriptions", "Add a subscription to a system"
|
|
api :POST, "/activation_keys/:activation_key_id/subscriptions", "Add a subscription to an activation key"
|
|
param :id, String, :desc => "Subscription Pool uuid"
|
|
param :system_id, String, :desc => "UUID of the system"
|
|
param :activation_key_id, String, :desc => "ID of the activation key"
|
|
param :quantity, :number, :desc => "Quantity of this subscriptions to add"
|
|
param :subscriptions, Array, :desc => "Array of subscriptions to add", :required => true do
|
|
param :subscription, Hash do
|
|
param :id, String, :desc => "Subscription Pool uuid", :required => true
|
|
param :quantity, :number, :desc => "Quantity of this subscriptions to add", :required => true
|
|
end
|
|
end
|
|
def create
|
|
object = @system || @activation_key || @distributor
|
|
subscription_params[:subscriptions].each do |subscription|
|
|
object.subscribe(subscription[:subscription][:id], subscription[:subscription][:quantity])
|
|
end if subscription_params[:subscriptions]
|
|
if subscription_params[:id] && subscription_params[:quantity]
|
|
object.subscribe(subscription_params[:id], subscription_params[:quantity])
|
|
end
|
|
|
|
subscriptions = if @system
|
|
index_system
|
|
elsif @activation_key
|
|
index_activation_key
|
|
else
|
|
index_organization
|
|
end
|
|
|
|
respond_for_index(:collection => subscriptions, :template => 'index')
|
|
end
|
|
|
|
api :DELETE, "/subscriptions/:id", "Unattach a subscription"
|
|
api :DELETE, "/systems/:system_id/subscriptions/:id", "Unattach a subscription"
|
|
api :DELETE, "/activation_keys/:activation_key_id/subscriptions/:id", "Unattach a subscription"
|
|
param :id, String, :desc => "Subscription ID"
|
|
param :system_id, String, :desc => "UUID of the system"
|
|
param :activation_key_id, String, :desc => "activation key ID"
|
|
def destroy
|
|
object = @system || @activation_key || @distributor
|
|
if params[:subscription].present?
|
|
subscription_params[:subscriptions].each do |subscription|
|
|
object.unsubscribe(subscription[:subscription][:id])
|
|
end
|
|
elsif params[:id]
|
|
object.unsubscribe(params[:id])
|
|
else
|
|
@system.unsubscribe_all
|
|
end
|
|
|
|
subscriptions = if @system
|
|
index_system
|
|
elsif @activation_key
|
|
index_activation_key
|
|
else
|
|
index_organization
|
|
end
|
|
|
|
respond_for_index(:collection => subscriptions, :template => 'index')
|
|
end
|
|
|
|
api :POST, "/organizations/:organization_id/subscriptions/upload", "Upload a subscription manifest"
|
|
api :POST, "/subscriptions/upload", "Upload a subscription manifest"
|
|
param :organization_id, :identifier, :desc => "Organization id", :required => true
|
|
param :content, File, :desc => "Subscription manifest file", :required => true
|
|
def upload
|
|
fail HttpErrors::BadRequest, _("No manifest file uploaded") if params[:content].blank?
|
|
|
|
begin
|
|
# candlepin requires that the file has a zip file extension
|
|
temp_file = File.new(File.join("#{Rails.root}/tmp", "import_#{SecureRandom.hex(10)}.zip"), 'wb+', 0600)
|
|
temp_file.write params[:content].read
|
|
ensure
|
|
temp_file.close
|
|
end
|
|
|
|
task = async_task(::Actions::Katello::Provider::ManifestImport, @provider, File.expand_path(temp_file.path), params[:force])
|
|
respond_for_async :resource => task
|
|
end
|
|
|
|
api :PUT, "/organizations/:organization_id/subscriptions/refresh_manifest", "Refresh previously imported manifest for Red Hat provider"
|
|
param :organization_id, :identifier, :desc => "Organization id", :required => true
|
|
def refresh_manifest
|
|
details = @provider.organization.owner_details
|
|
upstream = details['upstreamConsumer'].blank? ? {} : details['upstreamConsumer']
|
|
|
|
task = async_task(::Actions::Katello::Provider::ManifestRefresh, @provider, upstream)
|
|
respond_for_async :resource => task
|
|
end
|
|
|
|
api :POST, "/organizations/:organization_id/subscriptions/delete_manifest", "Delete manifest from Red Hat provider"
|
|
param :organization_id, :identifier, :desc => "Organization id", :required => true
|
|
def delete_manifest
|
|
task = async_task(::Actions::Katello::Provider::ManifestDelete, @provider)
|
|
respond_for_async :resource => task
|
|
end
|
|
|
|
protected
|
|
|
|
def find_system
|
|
@system = System.find_by_uuid!(params[:system_id]) if params[:system_id]
|
|
end
|
|
|
|
def find_activation_key
|
|
@activation_key = ActivationKey.find_by_id!(params[:activation_key_id]) if params[:activation_key_id]
|
|
end
|
|
|
|
def find_provider
|
|
@organization = @system.organization if @system
|
|
@organization = @activation_key.organization if @activation_key
|
|
@organization = @subscription.organization if @subscription
|
|
@provider = @organization.redhat_provider if @organization
|
|
end
|
|
|
|
def find_subscription
|
|
@subscription = Pool.find_by_id!(params[:id])
|
|
end
|
|
|
|
private
|
|
|
|
def index_system
|
|
subs = @system.consumed_entitlements
|
|
# TODO: pluck id and call elasticsearch?
|
|
subscriptions = {
|
|
:results => subs,
|
|
:subtotal => subs.count,
|
|
:total => subs.count,
|
|
:page => 1,
|
|
:per_page => subs.count
|
|
}
|
|
|
|
return subscriptions
|
|
end
|
|
|
|
def index_activation_key
|
|
@organization = @activation_key.organization
|
|
subs = activation_key_subscriptions(@activation_key.get_key_pools)
|
|
# TODO: pluck id and call elasticsearch?
|
|
subscriptions = {
|
|
:results => subs,
|
|
:subtotal => subs.count,
|
|
:total => subs.count,
|
|
:page => 1,
|
|
:per_page => subs.count
|
|
}
|
|
|
|
return subscriptions
|
|
end
|
|
|
|
def index_organization
|
|
filters = []
|
|
filters << {:term => {:org => [@organization.label]}}
|
|
|
|
options = {
|
|
:filters => filters,
|
|
:load_records? => false,
|
|
:default_field => :product_name
|
|
}
|
|
|
|
# TODO: remove this fragile logic
|
|
# Without any search terms, reindex all subscriptions in elasticsearch. This is to ensure
|
|
# that the latest information is searchable.
|
|
if params[:offset].to_i == 0 && params[:search].blank?
|
|
@organization.redhat_provider.index_subscriptions
|
|
end
|
|
|
|
subscriptions = item_search(Pool, params, options)
|
|
|
|
return subscriptions
|
|
end
|
|
|
|
api :GET, "/systems/:system_id/subscriptions/available", "List available subscriptions"
|
|
param :system_id, String, :desc => "UUID of the system", :required => true
|
|
param :match_system, :bool, :desc => "Return subscriptions that match system"
|
|
param :match_installed, :bool, :desc => "Return subscriptions that match installed"
|
|
param :no_overlap, :bool, :desc => "Return subscriptions that don't overlap"
|
|
def available_system
|
|
params[:match_system] = params[:match_system].to_bool if params[:match_system]
|
|
params[:match_installed] = params[:match_installed].to_bool if params[:match_installed]
|
|
params[:no_overlap] = params[:no_overlap].to_bool if params[:no_overlap]
|
|
pools = @system.filtered_pools(params[:match_system], params[:match_installed],
|
|
params[:no_overlap])
|
|
available = available_subscriptions(pools, @system.organization)
|
|
|
|
subscriptions = {
|
|
:results => available,
|
|
:subtotal => available.count,
|
|
:total => available.count
|
|
}
|
|
|
|
return subscriptions
|
|
end
|
|
|
|
def available_activation_key
|
|
@organization = @activation_key.organization
|
|
all_pools = @activation_key.get_pools
|
|
key_pool_ids = @activation_key.get_key_pools.collect {|pool| pool[:id]}
|
|
pools = all_pools.collect {|pool| pool if !key_pool_ids.include? pool[:id]}.compact
|
|
subs = activation_key_subscriptions(pools)
|
|
subscriptions = {
|
|
:results => subs,
|
|
:subtotal => subs.count,
|
|
:total => subs.count,
|
|
:page => 1,
|
|
:per_page => subs.count
|
|
}
|
|
|
|
return subscriptions
|
|
end
|
|
|
|
def available_organization
|
|
# TODO: perhaps /organizations/:organization_id/available to return just subs w/ unused quantity?
|
|
# TODO: or just those w/ repos enabled? (eg. sub-mgr list --available)
|
|
|
|
filters = []
|
|
filters << {:terms => {:cp_id => subscriptions.collect(&:cp_id)}}
|
|
filters << {:term => {:org => [@organization.label]}}
|
|
filters << {:term => {:provider_id => [@organization.redhat_provider.id]}}
|
|
options = {
|
|
:filters => filters,
|
|
:load_records? => false,
|
|
:default_field => :product_name
|
|
}
|
|
|
|
# TODO: remove this fragile logic
|
|
# Without any search terms, reindex all subscriptions in elasticsearch. This is to ensure
|
|
# that the latest information is searchable.
|
|
if params[:offset].to_i == 0 && params[:search].blank?
|
|
@organization.redhat_provider.index_subscriptions
|
|
end
|
|
|
|
subscriptions = item_search(Pool, params, options)
|
|
|
|
return subscriptions
|
|
end
|
|
|
|
def activation_key_subscriptions(cp_pools)
|
|
if cp_pools
|
|
pools = cp_pools.collect{|cp_pool| Pool.find_pool(cp_pool['id'], cp_pool)}
|
|
|
|
subscriptions = pools.collect do |pool|
|
|
product = Product.where(:cp_id => pool.product_id).first
|
|
next if product.nil?
|
|
pool.provider_id = product.provider_id
|
|
pool
|
|
end
|
|
subscriptions.compact!
|
|
else
|
|
subscriptions = []
|
|
end
|
|
|
|
return subscriptions
|
|
end
|
|
|
|
def subscription_params
|
|
params.require(:subscription).permit(:id, :quantity, :subscriptions => [:subscription => [:id, :quantity]])
|
|
params[:subscription]
|
|
end
|
|
|
|
end
|
|
end
|