Project

General

Profile

Download (17.5 KB) Statistics
| Branch: | Tag: | Revision:
#
# 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::V1::CandlepinProxiesController < Api::V1::ApiController

include Katello::Authentication::RhsmAuthentication

skip_before_filter :authorize
before_filter :authorize_rhsm, :except => [:consumer_activate]
before_filter :add_candlepin_version_header

before_filter :proxy_request_path, :proxy_request_body
before_filter :set_organization_id
before_filter :find_organization, :only => [:rhsm_index, :consumer_activate]
before_filter :find_default_organization_and_or_environment, :only => [:consumer_create, :index, :consumer_activate]
before_filter :find_optional_organization, :only => [:consumer_create, :hypervisors_update, :index, :consumer_activate]
before_filter :find_only_environment, :only => [:consumer_create]
before_filter :find_environment, :only => [:index]
before_filter :find_environment_and_content_view, :only => [:consumer_create]
before_filter :find_content_view, :only => [:consumer_create, :facts]
before_filter :find_hypervisor_environment_and_content_view, :only => [:hypervisors_update]
before_filter :find_system, :only => [:consumer_show, :consumer_destroy, :consumer_checkin,
:upload_package_profile, :regenerate_identity_certificates, :facts]
before_filter :find_user_by_login, :only => [:list_owners]

# TODO: break up method
# rubocop:disable MethodLength
def rules

proxy_test = lambda do
route, _, params = Engine.routes.router.recognize(request) do |rte, match, parameters|
break rte, match, parameters if rte.name
end

# route names are defined in routes.rb (:as => :name)
case route.name
when "api_proxy_consumer_deletionrecord_delete_path"
User.consumer? || Organization.all_editable?
when "api_proxy_owner_pools_path"
find_optional_organization
if params[:consumer]
(User.consumer? || @organization.readable?) && current_user.uuid == params[:consumer]
else
(User.consumer? || @organization.readable?)
end
when "api_proxy_owner_servicelevels_path"
find_optional_organization
(User.consumer? || @organization.readable?)
when "api_proxy_consumer_certificates_path", "api_proxy_consumer_releases_path", "api_proxy_certificate_serials_path",
"api_proxy_consumer_entitlements_path", "api_proxy_consumer_entitlements_post_path", "api_proxy_consumer_entitlements_delete_path",
"api_proxy_consumer_dryrun_path", "api_proxy_consumer_owners_path", "api_proxy_consumer_compliance_path",
"api_proxy_consumer_content_overrides_path"
User.consumer? && current_user.uuid == params[:id]
when "api_proxy_consumer_certificates_delete_path"
User.consumer? && current_user.uuid == params[:consumer_id]
when "api_proxy_pools_path"
User.consumer? && current_user.uuid == params[:consumer]
when "api_proxy_entitlements_path"
User.consumer?
when "api_proxy_subscriptions_post_path"
User.consumer? && current_user.uuid == params[:consumer_uuid]
when "api_proxy_deleted_consumers_path"
current_user.has_superadmin_role?
else
Rails.logger.warn "Unknown proxy route #{request.method} #{request.fullpath}, access denied"
false
end
end
# After a system registers, it immediately uploads its packages. Although newer subscription-managers send
# certificate (User.consumer? == true), some do not. In this case, confirm that the user has permission to
# register systems in the system's organization and environment.
upload_system_packages = lambda do
@system.editable? ||
System.registerable?(@system.environment, @system.organization) ||
User.consumer?
end
consumer_only = lambda { User.consumer? }
list_owners_test = lambda { @user.id == User.current.id } #user can see only his/her owners
register_system = lambda { System.registerable?(@environment, @organization, @content_view) }
index_systems = lambda { System.any_readable?(@organization) }
edit_system = lambda do
subscribable = @content_view ? @content_view.subscribable? : true
subscribable && (@system.editable? || User.consumer?)
end

{
:get => proxy_test,
:post => proxy_test,
:put => proxy_test,
:delete => proxy_test,
:upload_package_profile => upload_system_packages,
:consumer_checkin => consumer_only,
:regenerate_identity_certificates => consumer_only,
:consumer_create => register_system,
:consumer_destroy => consumer_only,
:consumer_show => consumer_only,
:consumer_activate => register_system,
:index => index_systems,
:hypervisors_update => consumer_only,
:list_owners => list_owners_test,
:rhsm_index => lambda {true},
:facts => edit_system
}
end

rescue_from RestClient::Exception do |e|
Rails.logger.error pp_exception(e)
if request_from_katello_cli?
render :json => { :errors => [e.http_body] }, :status => e.http_code
else
render :text => e.http_body, :status => e.http_code
end
end

def proxy_request_path
@request_path = drop_api_namespace(@_request.fullpath)
end

def proxy_request_body
@request_body = @_request.body
end

def drop_api_namespace(original_request_path)
prefix = "#{Katello.config.url_prefix}/api"
original_request_path.gsub(prefix, '')
end

def get
r = Resources::Candlepin::Proxy.get(@request_path)
logger.debug r
render :json => r
end

def delete
r = Resources::Candlepin::Proxy.delete(@request_path)
logger.debug r
render :json => r
end

def post
r = Resources::Candlepin::Proxy.post(@request_path, @request_body)
logger.debug r
render :json => r
end

#api :GET, "/consumers/:id", "Show a system"
#param :id, String, :desc => "UUID of the consumer", :required => true
def consumer_show
render :json => Resources::Candlepin::Consumer.get(@system.uuid)
end

#api :GET, "/owners/:organization_id/environments", "List environments for RHSM"
def rhsm_index
@all_environments = get_content_view_environments(query_params[:name]).collect do |env|
{
:id => env.cp_id,
:name => env.label,
:display_name => env.name,
:description => env.content_view.description
}
end

respond_for_index :collection => @all_environments
end

#api :POST, "/hypervisors", "Update the hypervisors information for environment"
#desc 'See virt-who tool for more details.'
def hypervisors_update
cp_response, _ = System.register_hypervisors(@environment, @content_view, params.except(:controller, :action, :format))
render :json => cp_response
end

#api :PUT, "/consumers/:id/checkin/", "Update consumer check-in time"
#param :date, String, :desc => "check-in time"
def consumer_checkin
@system.checkin(params[:date])
render :json => Resources::Candlepin::Consumer.get(@system.uuid)
end

#api :PUT, "/consumers/:id/packages", "Update installed packages"
#api :PUT, "/consumers/:id/profile", "Update installed packages"
#param :id, String, :desc => "UUID of the consumer", :required => true
def upload_package_profile
allowed = rules[:upload_package_profile].call
if allowed
fail HttpErrors::BadRequest, _("No package profile received for %s") % @system.name unless params.key?(:_json)
@system.upload_package_profile(params[:_json])
render :json => Resources::Candlepin::Consumer.get(@system.uuid)
else
Rails.logger.warn(_("Consumer %s not allowed to upload package profile.") % params[:id])
respond_for_update :resource => {}
end
end

def list_owners
orgs = @user.allowed_organizations
# rhsm expects owner (Candlepin format)
# rubocop:disable SymbolName
respond_for_index :collection => orgs.map { |o| { :key => o.label, :displayName => o.name } }
end

#api :POST, "/consumers/:id", "Regenerate consumer identity"
#param :id, String, :desc => "UUID of the consumer"
#desc 'Schedules the consumer identity certificate regeneration'
def regenerate_identity_certificates
@system.regenerate_identity_certificates
render :json => Resources::Candlepin::Consumer.get(@system.uuid)
end

#api :POST, "/environments/:environment_id/consumers", "Register a consumer in environment"
def consumer_create
@system = System.new(system_params.merge(:environment => @environment,
:content_view => @content_view,
:serviceLevel => params[:service_level]))
sync_task(::Actions::Katello::System::Create, @system)
@system.reload
render :json => Resources::Candlepin::Consumer.get(@system.uuid)
end

#api :DELETE, "/consumers/:id", "Unregister a consumer"
#param :id, String, :desc => "UUID of the consumer", :required => true
def consumer_destroy
@system.destroy
render :text => _("Deleted consumer '%s'") % params[:id], :status => 204
end

# used for registering with activation keys
#api :POST, "/consumers", "Register a system with activation key (compatibility)"
#param :activation_keys, String, :required => true
def consumer_activate
# Activation keys are userless by definition so use the internal generic user
# Set it before calling find_activation_keys to allow communication with candlepin
User.current = User.hidden.first
activation_keys = find_activation_keys

@system = System.new(system_params.merge(:environment => activation_keys[0].environment,
:content_view => activation_keys[0].content_view))
sync_task(::Actions::Katello::System::Create, @system, activation_keys)
@system.reload

render :json => Resources::Candlepin::Consumer.get(@system.uuid)
end

def facts
attrs = params.clone
slice_attrs = [:name, :description, :location,
:facts, :guestIds, :installedProducts,
:releaseVer, :serviceLevel, :lastCheckin
]
attrs[:installedProducts] = [] if attrs.key?(:installedProducts) && attrs[:installedProducts].nil?

@system.update_attributes!(attrs.slice(*slice_attrs))

render :json => {:content => _("Facts successfully updated.")}, :status => 200
end

private

def set_organization_id
params[:organization_id] = params[:owner] if params[:owner]
end

def find_system
@system = System.first(:conditions => { :uuid => params[:id] })
if @system.nil?
# check with candlepin if consumer is Gone, raises RestClient::Gone
Resources::Candlepin::Consumer.get params[:id]
fail HttpErrors::NotFound, _("Couldn't find consumer '%s'") % params[:id]
end
@system
end

def find_user_by_login
@user = User.find_by_login(params[:login])
fail HttpErrors::NotFound, _("Couldn't find user '%s'") % params[:login] if @user.nil?
@user
end

def find_default_organization_and_or_environment
# This has to grab the first default org associated with this user AND
# the environment that goes with him.
return if params.key?(:organization_id) || params.key?(:owner) || params.key?(:environment_id)

#At this point we know that they didn't supply an org or environment, so we can look up the default
@environment = current_user.default_environment
if @environment
@organization = @environment.organization
else
fail HttpErrors::NotFound, _("You have not set a default organization and environment on the user %s.") % current_user.login
end
end

def find_only_environment
if !@environment && @organization && !params.key?(:environment_id)
if @organization.environments.empty?
fail HttpErrors::BadRequest, _("Organization %{org} has the '%{env}' environment only. Please create an environment for system registration.") %
{ :org => @organization.name, :env => "Library" }
end

# Some subscription-managers will call /users/$user/owners to retrieve the orgs that a user belongs to.
# Then, If there is just one org, that will be passed to the POST /api/consumers as the owner. To handle
# this scenario, if the org passed in matches the user's default org, use the default env. If not use
# the single env of the org or throw an error if more than one.
#
if @organization.environments.size > 1
if current_user.default_environment && current_user.default_environment.organization == @organization
@environment = current_user.default_environment
else
fail HttpErrors::BadRequest, _("Organization %s has more than one environment. Please specify target environment for system registration.") % @organization.name
end
else
if @environment = @organization.environments.first
return
end
end
end
end

def find_content_view
if (content_view_id = (params[:content_view_id] || params[:system].try(:[], :content_view_id)))
setup_content_view(content_view_id)
end
end

def find_environment_and_content_view
# There are some scenarios (primarily create) where a system may be
# created using the content_view_environment.cp_id which is the
# equivalent of "environment_id"-"content_view_id".
return unless params.key?(:environment_id)

if params[:environment_id].is_a? String
if !params.key?(:content_view_id)
cve = get_content_view_environment_by_cp_id(params[:environment_id])
@environment = cve.environment
@organization = @environment.organization
@content_view = cve.content_view
else
# assumption here is :content_view_id is passed as a separate attrib
@environment = KTEnvironment.find(params[:environment_id])
@organization = @environment.organization
fail HttpErrors::NotFound, _("Couldn't find environment '%s'") % params[:environment_id] if @environment.nil?
end
return @environment, @content_view
else
find_environment
end
end

def find_hypervisor_environment_and_content_view
cve = get_content_view_environment_by_label(params[:env])
@environment = cve.environment
@content_view = cve.content_view
end

def find_activation_keys
if ak_names = params[:activation_keys]
ak_names = ak_names.split(",")
activation_keys = ak_names.map do |ak_name|
activation_key = @organization.activation_keys.find_by_name(ak_name)
fail HttpErrors::NotFound, _("Couldn't find activation key '%s'") % ak_name unless activation_key
activation_key
end
else
activation_keys = []
end
if activation_keys.empty?
fail HttpErrors::BadRequest, _("At least one activation key must be provided")
end
activation_keys
end

def get_content_view_environment_by_label(label)
get_content_view_environment("label", label)
end

def get_content_view_environment(key, value)
cve = nil
if value
cve = ContentViewEnvironment.where(key => value).first
fail HttpErrors::NotFound, _("Couldn't find environment '%s'") % value unless cve
if @organization.nil? || !@organization.readable?
unless cve.content_view.readable? || User.consumer?
fail Errors::SecurityViolation, _("Could not access content view in environment '%s'") % value
end
end
end
cve
end

def get_content_view_environment_by_cp_id(id)
get_content_view_environment("cp_id", id)
end

def get_content_view_environments(label = nil)
environments = ContentViewEnvironment.joins(:content_view => :organization).
where("#{Organization.table_name}.id = ?", @organization.id)
environments = environments.where("#{Katello::ContentViewEnvironment.table_name}.label = ?", label) if label

# remove any content view environments that aren't readable
unless @organization.readable?
environments.delete_if do |env|
!env.content_view.readable?
end
end
environments
end

def system_params
system_params = params.slice(:name, :owner, :facts, :installedProducts)

if params.key?(:cp_type)
system_params[:cp_type] = params[:cp_type]
elsif params.key?(:type)
system_params[:cp_type] = params[:type]
end

system_params
end

def logger
::Logging.logger['cp_proxy']
end

end
end
(4-4/39)