app/controllers/katello/api/v2/repositories_controller.rb in katello-3.6.0.1.rc2 vs app/controllers/katello/api/v2/repositories_controller.rb in katello-3.7.0.rc1
- old
+ new
@@ -1,28 +1,39 @@
module Katello
class Api::V2::RepositoriesController < Api::V2::ApiController # rubocop:disable Metrics/ClassLength
include Katello::Concerns::FilteredAutoCompleteSearch
+ CONTENT_CREDENTIAL_GPG_KEY_TYPE = "gpg_key".freeze
+ CONTENT_CREDENTIAL_SSL_CA_CERT_TYPE = "ssl_ca_cert".freeze
+ CONTENT_CREDENTIAL_SSL_CLIENT_CERT_TYPE = "ssl_client_cert".freeze
+ CONTENT_CREDENTIAL_SSL_CLIENT_KEY_TYPE = "ssl_client_key".freeze
+
before_action :find_optional_organization, :only => [:index, :auto_complete_search]
before_action :find_product, :only => [:index, :auto_complete_search]
before_action :find_product_for_create, :only => [:create]
before_action :find_organization_from_product, :only => [:create]
before_action :find_repository, :only => [:show, :update, :destroy, :sync, :export,
:remove_content, :upload_content, :republish,
:import_uploads, :gpg_key_content]
before_action :find_content, :only => :remove_content
before_action :find_organization_from_repo, :only => [:update]
- before_action :find_gpg_key, :only => [:create, :update]
+ before_action :only => [:create, :update] { find_content_credential CONTENT_CREDENTIAL_GPG_KEY_TYPE }
+ before_action :only => [:create, :update] { find_content_credential CONTENT_CREDENTIAL_SSL_CA_CERT_TYPE }
+ before_action :only => [:create, :update] { find_content_credential CONTENT_CREDENTIAL_SSL_CLIENT_CERT_TYPE }
+ before_action :only => [:create, :update] { find_content_credential CONTENT_CREDENTIAL_SSL_CLIENT_KEY_TYPE }
before_action :error_on_rh_product, :only => [:create]
before_action :error_on_rh_repo, :only => [:destroy]
skip_before_action :authorize, :only => [:sync_complete, :gpg_key_content]
skip_before_action :check_content_type, :only => [:upload_content]
def_param_group :repo do
param :url, String, :desc => N_("repository source url")
param :gpg_key_id, :number, :desc => N_("id of the gpg key that will be assigned to the new repository")
+ param :ssl_ca_cert_id, :number, :desc => N_("Idenifier of the SSL CA Cert")
+ param :ssl_client_cert_id, :number, :desc => N_("Identifier of the SSL Client Cert")
+ param :ssl_client_key_id, :number, :desc => N_("Identifier of the SSL Client Key")
param :unprotected, :bool, :desc => N_("true if this repository can be published via HTTP")
param :checksum_type, String, :desc => N_("checksum of the repository, currently 'sha1' & 'sha256' are supported.")
param :docker_upstream_name, String, :desc => N_("name of the upstream docker repository")
param :download_policy, ["immediate", "on_demand", "background"], :desc => N_("download policy for yum repos (either 'immediate', 'on_demand', or 'background')")
param :mirror_on_sync, :bool, :desc => N_("true if this repository when synced has to be mirrored from the source and stale rpms removed.")
@@ -33,10 +44,11 @@
param :ostree_upstream_sync_depth, :number, :desc => N_("if a custom sync policy is chosen for ostree repositories then a 'depth' value must be provided.")
param :deb_releases, String, :desc => N_("comma separated list of releases to be synched from deb-archive")
param :deb_components, String, :desc => N_("comma separated list of repo components to be synched from deb-archive")
param :deb_architectures, String, :desc => N_("comma separated list of architectures to be synched from deb-archive")
param :ignore_global_proxy, :bool, :desc => N_("if true, will ignore the globally configured proxy when syncing.")
+ param :ignorable_content, Array, :desc => N_("List of content units to ignore while syncing a yum repository. Must be subset of %s") % Repository::IGNORABLE_CONTENT_UNIT_TYPES.join(",")
end
def_param_group :repo_create do
param :label, String, :required => false
param :product_id, :number, :required => true, :desc => N_("Product the repository belongs to")
@@ -63,12 +75,32 @@
param :name, String, :desc => N_("name of the repository"), :required => false
param :available_for, String, :desc => N_("interpret specified object to return only Repositories that can be associated with specified object. Only 'content_view' is supported."),
:required => false
param_group :search, Api::V2::ApiController
def index
+ base_args = [index_relation.distinct, :name, :asc]
options = {:includes => [:gpg_key, :product, :environment]}
- respond(:collection => scoped_search(index_relation.distinct, :name, :asc, options))
+
+ respond_to do |format|
+ format.csv do
+ options[:csv] = true
+ repos = scoped_search(*base_args, options)
+ csv_response(repos,
+ [:id, :name, :label, :content_type, :arch, :url, :major, :minor,
+ :cp_label, :content_label, :pulp_id, :container_repository_name,
+ :download_policy, 'relative_path', 'product.id', 'product.name',
+ 'environment_id'],
+ ['Id', 'Name', 'label', 'Content Type', 'Arch', 'Url', 'Major', 'Minor',
+ 'Candlepin Label', 'Content Label', 'Pulp Id', 'Container Repository Name',
+ 'Download Policy', 'Relative Path', 'Product Id', 'Product Name',
+ 'Environment Id'])
+ end
+ format.any do
+ repos = scoped_search(*base_args, options)
+ respond(:collection => repos)
+ end
+ end
end
def index_relation
query = Repository.readable
query = index_relation_product(query)
@@ -140,42 +172,32 @@
api :POST, "/repositories", N_("Create a custom repository")
param :name, String, :required => true
param_group :repo_create
param_group :repo
- def create # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity
+ def create
repo_params = repository_params
unless RepositoryTypeManager.creatable_by_user?(repo_params[:content_type])
msg = _("Invalid params provided - content_type must be one of %s") % RepositoryTypeManager.creatable_repository_types.keys.join(",")
fail HttpErrors::UnprocessableEntity, msg
end
- gpg_key = @product.gpg_key
- unless repo_params[:gpg_key_id].blank?
- gpg_key = @gpg_key
- end
+ gpg_key = get_content_credential(repo_params, CONTENT_CREDENTIAL_GPG_KEY_TYPE)
+ ssl_ca_cert = get_content_credential(repo_params, CONTENT_CREDENTIAL_SSL_CA_CERT_TYPE)
+ ssl_client_cert = get_content_credential(repo_params, CONTENT_CREDENTIAL_SSL_CLIENT_CERT_TYPE)
+ ssl_client_key = get_content_credential(repo_params, CONTENT_CREDENTIAL_SSL_CLIENT_KEY_TYPE)
+
repo_params[:label] = labelize_params(repo_params)
repo_params[:arch] = repo_params[:arch] || 'noarch'
repo_params[:url] = nil if repo_params[:url].blank?
repo_params[:unprotected] = repo_params.key?(:unprotected) ? repo_params[:unprotected] : true
repo_params[:gpg_key] = gpg_key
- repository = @product.add_repo(Hash[repo_params.slice(:label, :name, :url, :content_type, :arch, :unprotected, :gpg_key, :checksum_type, :download_policy).to_h.map { |k, v| [k.to_sym, v] }])
- repository.docker_upstream_name = repo_params[:docker_upstream_name] if repo_params[:docker_upstream_name]
- repository.mirror_on_sync = ::Foreman::Cast.to_bool(repo_params[:mirror_on_sync]) if repo_params.key?(:mirror_on_sync)
- repository.ignore_global_proxy = ::Foreman::Cast.to_bool(repo_params[:ignore_global_proxy]) if repo_params.key?(:ignore_global_proxy)
- repository.verify_ssl_on_sync = ::Foreman::Cast.to_bool(repo_params[:verify_ssl_on_sync]) if repo_params.key?(:verify_ssl_on_sync)
- repository.upstream_username = repo_params[:upstream_username] if repo_params.key?(:upstream_username)
- repository.upstream_password = repo_params[:upstream_password] if repo_params.key?(:upstream_password)
- if repository.ostree?
- repository.ostree_upstream_sync_policy = repo_params[:ostree_upstream_sync_policy]
- repository.ostree_upstream_sync_depth = repo_params[:ostree_upstream_sync_depth]
- end
- if repository.deb?
- repository.deb_releases = repo_params[:deb_releases] if repo_params[:deb_releases]
- repository.deb_components = repo_params[:deb_components] if repo_params[:deb_components]
- repository.deb_architectures = repo_params[:deb_architectures] if repo_params[:deb_architectures]
- end
+ repo_params[:ssl_ca_cert] = ssl_ca_cert
+ repo_params[:ssl_client_cert] = ssl_client_cert
+ repo_params[:ssl_client_key] = ssl_client_key
+
+ repository = construct_repo_from_params(repo_params)
sync_task(::Actions::Katello::Repository::Create, repository, false, true)
repository = Repository.find(repository.id)
respond_for_show(:resource => repository)
end
@@ -246,10 +268,12 @@
end
end
fail HttpErrors::BadRequest, _("Repository content type must be 'yum' to export.") unless @repository.content_type == 'yum'
+ fail HttpErrors::BadRequest, _("On demand repositories cannot be exported.") if @repository.download_policy == ::Runcible::Models::YumImporter::DOWNLOAD_ON_DEMAND
+
task = async_task(::Actions::Katello::Repository::Export, [@repository],
::Foreman::Cast.to_bool(params[:export_to_iso]),
params[:since].try(:to_datetime),
params[:iso_mb_size],
@repository.pulp_id)
@@ -317,11 +341,11 @@
api :POST, "/repositories/:id/upload_content", N_("Upload content into the repository")
param :id, :number, :required => true, :desc => N_("repository ID")
param :content, File, :required => true, :desc => N_("Content files to upload. Can be a single file or array of files.")
def upload_content
- fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload Docker content.") if @repository.docker?
+ fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload Container Image content.") if @repository.docker?
filepaths = Array.wrap(params[:content]).compact.collect do |content|
{path: content.path, filename: content.original_filename}
end
@@ -349,41 +373,44 @@
param 'sync_capsule', :bool, :desc => N_("Whether or not to sync an external capsule after upload. Default: true")
param :uploads, Array, :desc => N_("Array of uploads to import") do
param 'id', String, :required => true
param 'size', String
param 'checksum', String
- param 'name', String, :desc => N_("Needs to only be set for file repositories")
+ param 'name', String, :desc => N_("Needs to only be set for file repositories or docker tags")
+ param 'digest', String, :desc => N_("Needs to only be set for docker tags")
end
def import_uploads
generate_metadata = ::Foreman::Cast.to_bool(params.fetch(:publish_repository, true))
sync_capsule = ::Foreman::Cast.to_bool(params.fetch(:sync_capsule, true))
async = ::Foreman::Cast.to_bool(params.fetch(:async, false))
if params['upload_ids'].empty? && params['uploads'].empty?
fail HttpErrors::BadRequest, _('No upload param specified. Either uploads or upload_ids (deprecated) is required.')
end
uploads = (params[:uploads] || []).map do |upload|
- upload.permit(:id, :size, :checksum, :name).to_h
+ upload.permit(:id, :size, :checksum, :name, :digest).to_h
end
if params.key?(:upload_ids)
::Foreman::Deprecation.api_deprecation_warning("The parameter upload_ids will be removed in Katello 3.3. Please update to use the uploads parameter.")
params[:upload_ids].each { |upload_id| uploads << {'id' => upload_id} }
end
upload_ids = uploads.map { |upload| upload['id'] }
unit_keys = uploads.map do |upload|
- if @repository.file?
+ if @repository.file? || @repository.docker?
upload.except('id')
else
upload.except('id').except('name')
end
end
+ unit_type_id = unit_keys[0] && unit_keys[0].include?('digest') ? 'docker_tag' : @repository.unit_type_id
+
begin
task = send(async ? :async_task : :sync_task, ::Actions::Katello::Repository::ImportUpload,
- @repository, upload_ids, :unit_keys => unit_keys,
+ @repository, upload_ids, :unit_type_id => unit_type_id, :unit_keys => unit_keys,
:generate_metadata => generate_metadata, :sync_capsule => sync_capsule)
respond_for_async(resource: task)
rescue => e
raise HttpErrors::BadRequest, e.message
end
@@ -415,26 +442,68 @@
def find_repository
@repository = Repository.find(params[:id])
end
- def find_gpg_key
- if params[:gpg_key_id]
- @gpg_key = GpgKey.readable.where(:id => params[:gpg_key_id], :organization_id => @organization).first
- fail HttpErrors::NotFound, _("Couldn't find gpg key '%s'") % params[:gpg_key_id] if @gpg_key.nil?
+ def find_content_credential(content_type)
+ credential_id = "#{content_type}_id".to_sym
+ credential_var = "@#{content_type}"
+
+ if params[credential_id]
+ credential_value = GpgKey.readable.where(:id => params[credential_id], :organization_id => @organization).first
+ instance_variable_set(credential_var, credential_value)
+ if instance_variable_get(credential_var).nil?
+ fail HttpErrors::NotFound, _("Couldn't find %{content_type} with id '%{id}'") % { :content_type => content_type, :id => params[credential_id] }
+ end
end
end
def repository_params
keys = [:download_policy, :mirror_on_sync, :arch, :verify_ssl_on_sync, :upstream_password, :upstream_username,
:ostree_upstream_sync_depth, :ostree_upstream_sync_policy, :ignore_global_proxy,
- :deb_releases, :deb_components, :deb_architectures
+ :deb_releases, :deb_components, :deb_architectures, {:ignorable_content => []}
]
+
keys += [:label, :content_type] if params[:action] == "create"
if params[:action] == 'create' || @repository.custom?
- keys += [:url, :gpg_key_id, :unprotected, :name, :checksum_type, :docker_upstream_name]
+ keys += [:url, :gpg_key_id, :ssl_ca_cert_id, :ssl_client_cert_id, :ssl_client_key_id, :unprotected, :name, :checksum_type, :docker_upstream_name]
end
params.require(:repository).permit(*keys).to_h
+ end
+
+ def get_content_credential(repo_params, content_type)
+ credential_value = @product.send(content_type)
+
+ unless repo_params["#{content_type}_id".to_sym].blank?
+ credential_value = instance_variable_get("@#{content_type}")
+ end
+
+ credential_value
+ end
+
+ def construct_repo_from_params(repo_params)
+ repository = @product.add_repo(Hash[repo_params.slice(:label, :name, :url, :content_type, :arch, :unprotected,
+ :gpg_key, :ssl_ca_cert, :ssl_client_cert, :ssl_client_key,
+ :checksum_type, :download_policy).to_h.map { |k, v| [k.to_sym, v] }])
+ repository.docker_upstream_name = repo_params[:docker_upstream_name] if repo_params[:docker_upstream_name]
+ repository.mirror_on_sync = ::Foreman::Cast.to_bool(repo_params[:mirror_on_sync]) if repo_params.key?(:mirror_on_sync)
+ repository.ignore_global_proxy = ::Foreman::Cast.to_bool(repo_params[:ignore_global_proxy]) if repo_params.key?(:ignore_global_proxy)
+ repository.verify_ssl_on_sync = ::Foreman::Cast.to_bool(repo_params[:verify_ssl_on_sync]) if repo_params.key?(:verify_ssl_on_sync)
+ repository.upstream_username = repo_params[:upstream_username] if repo_params.key?(:upstream_username)
+ repository.upstream_password = repo_params[:upstream_password] if repo_params.key?(:upstream_password)
+ repository.ignorable_content = repo_params[:ignorable_content] if repository.yum? && repo_params.key?(:ignorable_content)
+
+ if repository.ostree?
+ repository.ostree_upstream_sync_policy = repo_params[:ostree_upstream_sync_policy]
+ repository.ostree_upstream_sync_depth = repo_params[:ostree_upstream_sync_depth]
+ end
+ if repository.deb?
+ repository.deb_releases = repo_params[:deb_releases] if repo_params[:deb_releases]
+ repository.deb_components = repo_params[:deb_components] if repo_params[:deb_components]
+ repository.deb_architectures = repo_params[:deb_architectures] if repo_params[:deb_architectures]
+ end
+
+ repository
end
def error_on_rh_product
fail HttpErrors::BadRequest, _("Red Hat products cannot be manipulated.") if @product.redhat?
end