Skip to content

Commit

Permalink
Fixes #22909 - Remove subscriptions from upstream allocation
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathon Turel committed Mar 29, 2018
1 parent 1066301 commit 6ebefb0
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 5 deletions.
@@ -1,5 +1,3 @@
require 'katello/resources/candlepin'

module Katello
class Api::V2::UpstreamSubscriptionsController < Api::V2::ApiController
before_action :check_disconnected
Expand All @@ -26,6 +24,14 @@ def index
respond(collection: collection)
end

api :DELETE, "/upstream_subscriptions",
N_("Remove one or more subscriptions from an upstream subscription allocation")
param :pool_ids, Array, desc: N_("Array of local pool IDs. Only pools originating upstream (non-custom) are accepted."), required: true
def destroy
task = async_task(::Actions::Katello::UpstreamSubscriptions::RemoveEntitlements, params[:pool_ids])
respond_for_async :resource => task
end

private

def upstream_pool_params
Expand Down
@@ -0,0 +1,22 @@
module Actions
module Katello
module UpstreamSubscriptions
class RemoveEntitlement < Actions::Base
middleware.use Actions::Middleware::KeepCurrentTaxonomies
middleware.use Actions::Middleware::PropagateCandlepinErrors

input_format do
param :entitlement_id
end

def run
output[:response] = ::Katello::Resources::Candlepin::UpstreamConsumer.remove_entitlement(input[:entitlement_id])
end

def run_progress_weight
0.01
end
end
end
end
end
@@ -0,0 +1,34 @@
module Actions
module Katello
module UpstreamSubscriptions
class RemoveEntitlements < Actions::Base
middleware.use Actions::Middleware::KeepCurrentTaxonomies

def plan(pool_ids = [])
ids = pool_ids.uniq.compact
fail("No pool IDs were provided.") if ids.blank?

sequence do
ids.each do |pid|
pool = ::Katello::Pool.find(pid)

fail("Provided pool with id #{pid} has no upstream entitlement") if pool.upstream_entitlement_id.nil?

plan_action(::Actions::Katello::UpstreamSubscriptions::RemoveEntitlement, entitlement_id: pool.upstream_entitlement_id)
end

plan_action(::Actions::Katello::Organization::ManifestRefresh, ::Organization.current)
end
end

def humanized_name
N_("Delete Upstream Subscription")
end

def rescue_strategy
Dynflow::Action::Rescue::Skip
end
end
end
end
end
5 changes: 5 additions & 0 deletions app/lib/katello/resources/candlepin.rb
Expand Up @@ -128,6 +128,11 @@ def resource(url = self.site + self.path, client_cert = self.client_cert, client
)
end

def json_resource(url = self.site + self.path, client_cert = self.client_cert, client_key = self.client_key, ca_file = nil, options = {})
options.deep_merge!(headers: self.default_headers)
resource(url, client_cert, client_key, ca_file, options)
end

def rest_client(_http_type = nil, method = :get, path = self.path)
# No oauth upstream
self.consumer_secret = nil
Expand Down
8 changes: 8 additions & 0 deletions app/lib/katello/resources/candlepin/consumer.rb
Expand Up @@ -214,6 +214,12 @@ def path(id = upstream_consumer_id)
super(id)
end

def remove_entitlement(entitlement_id)
fail ArgumentError, "No entitlement ID given to remove." if entitlement_id.blank?

self["entitlements/#{entitlement_id}"].delete
end

def export(url, client_cert, client_key, ca_file)
logger.debug "Sending GET request to upstream Candlepin: #{url}"
return resource(url, client_cert, client_key, ca_file).get
Expand All @@ -233,6 +239,8 @@ def update(url, client_cert, client_key, ca_file, attributes)
ensure
RestClient.proxy = ""
end

delegate :[], to: :json_resource
end
end
end # Candlepin
Expand Down
4 changes: 3 additions & 1 deletion app/models/katello/glue/candlepin/pool.rb
Expand Up @@ -10,7 +10,7 @@ def self.included(base)
lazy_accessor :subscription_facts, :initializer => lambda { |_s| self.subscription ? self.subscription.attributes : {} }

lazy_accessor :pool_derived, :owner, :source_pool_id, :virt_limit, :arch, :description,
:product_family, :variant, :suggested_quantity, :support_type, :product_id, :type,
:product_family, :variant, :suggested_quantity, :support_type, :product_id, :type, :upstream_entitlement_id,
:initializer => :pool_facts

lazy_accessor :name, :support_level, :org, :sockets, :cores, :stacking_id, :instance_multiplier,
Expand Down Expand Up @@ -64,6 +64,8 @@ def import_lazy_attributes

json["product_id"] = json["productId"] if json["productId"]

json["upstream_entitlement_id"] = json["upstreamEntitlementId"]

if self.subscription
subscription.backend_data["product"]["attributes"].map { |attr| json[attr["name"].underscore.to_sym] = attr["value"] }
end
Expand Down
6 changes: 5 additions & 1 deletion config/routes/api/v2.rb
Expand Up @@ -291,7 +291,11 @@ class ActionDispatch::Routing::Mapper
end
end

api_resources :upstream_subscriptions, only: :index
api_resources :upstream_subscriptions, only: :index do
collection do
delete :destroy
end
end

##############################
##############################
Expand Down
2 changes: 1 addition & 1 deletion lib/katello/permission_creator.rb
Expand Up @@ -351,7 +351,7 @@ def subscription_permissions # rubocop:disable Metrics/MethodLength
:resource_type => 'Katello::Subscription'
@plugin.permission :manage_subscription_allocations,
{
'katello/api/v2/upstream_subscriptions' => [:index]
'katello/api/v2/upstream_subscriptions' => [:index, :destroy]
},
:resource_type => 'Katello::Subscription'
end
Expand Down
@@ -0,0 +1,18 @@
require 'katello_test_helper'

describe ::Actions::Katello::UpstreamSubscriptions::RemoveEntitlement do
include Dynflow::Testing

subject { described_class }

before :all do
@org = FactoryBot.create(:katello_organization)
set_organization(@org)
@planned_action = create_and_plan_action(subject, org_id: @org.id, entitlement_id: 'foo')
end

it 'runs' do
::Katello::Resources::Candlepin::UpstreamConsumer.expects(:remove_entitlement).with('foo')
run_action @planned_action
end
end
@@ -0,0 +1,46 @@
require 'katello_test_helper'

describe ::Actions::Katello::UpstreamSubscriptions::RemoveEntitlements do
include Dynflow::Testing

subject { described_class }

before :all do
@org = FactoryBot.build(:katello_organization)
set_organization(@org)
@action = create_action(subject)
@remove_action_class = ::Actions::Katello::UpstreamSubscriptions::RemoveEntitlement
@manifest_action_class = ::Actions::Katello::Organization::ManifestRefresh
end

it 'plans' do
pool1 = katello_pools(:pool_one)
pool2 = katello_pools(:pool_two)

pool1.expects(:upstream_entitlement_id).returns('a').twice
pool2.expects(:upstream_entitlement_id).returns('b').twice

::Katello::Pool.expects(:find).with(pool1.id).returns(pool1)
::Katello::Pool.expects(:find).with(pool2.id).returns(pool2)

plan_action(@action, [pool1.id, pool2.id])

assert_action_planned_with(@action, @remove_action_class, entitlement_id: 'a')
assert_action_planned_with(@action, @remove_action_class, entitlement_id: 'b')
assert_action_planned_with(@action, @manifest_action_class, @org)
end

it 'raises an error when the pool has no upstream entitlement' do
pool1 = katello_pools(:pool_one)
pool1.expects(:upstream_entitlement_id).returns(nil)
::Katello::Pool.expects(:find).with(pool1.id).returns(pool1)

error = proc { plan_action(@action, [pool1.id]) }.must_raise RuntimeError
error.message.must_match(/upstream/)
end

it 'raises an error when given no entitlement ids' do
error = proc { plan_action(@action, []) }.must_raise RuntimeError
error.message.must_match(/provided/)
end
end
22 changes: 22 additions & 0 deletions test/controllers/api/v2/upstream_subscriptions_controller_test.rb
Expand Up @@ -4,6 +4,8 @@

module Katello
class Api::V2::UpstreamSubscriptionsControllerTest < ActionController::TestCase
include Support::ForemanTasks::Task

def models
@organization = get_organization
end
Expand Down Expand Up @@ -44,5 +46,25 @@ def test_index_disconnected
get :index, params: { organization_id: @organization.id }
assert_response :bad_request
end

def test_destroy
params = { pool_ids: %w(1 2 3)}
assert_async_task ::Actions::Katello::UpstreamSubscriptions::RemoveEntitlements do |entitlement_ids|
entitlement_ids.must_equal %w(1 2 3)
end

delete :destroy, params: params

assert_response :success
end

def test_destroy_protected
allowed_perms = [permission]
denied_perms = []

assert_protected_action(:destroy, allowed_perms, denied_perms, []) do
delete :destroy, params: { pool_ids: [] }
end
end
end
end
4 changes: 4 additions & 0 deletions test/katello_test_helper.rb
Expand Up @@ -191,6 +191,10 @@ def set_user(user = nil)
User.current = user
end

def set_organization(org)
Organization.current = org
end

def get_organization(org = nil)
saved_user = User.current
User.current = User.unscoped.find(users(:admin).id)
Expand Down

0 comments on commit 6ebefb0

Please sign in to comment.