Skip to content

Commit

Permalink
Merge pull request #4982 from jlsherrill/9120
Browse files Browse the repository at this point in the history
fixes #9120 - better feedback around composites for inc updates
  • Loading branch information
jlsherrill committed Feb 16, 2015
2 parents 4d9312c + 518ca32 commit 546cb7e
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 19 deletions.
17 changes: 13 additions & 4 deletions app/controllers/katello/api/v2/systems_bulk_actions_controller.rb
Expand Up @@ -168,12 +168,21 @@ def environment_content_view
def available_incremental_updates
version_environments = {}
systems = System.with_non_installable_errata(@errata).where("#{System.table_name}.id" => @systems)
systems.each do |system|
version = system.content_view.version(system.environment)

ContentViewEnvironment.for_systems(systems).each do |cve|
version = cve.content_view_version
version_environment = version_environments[version] || {:content_view_version => version, :environments => []}
version_environment[:environments] << system.environment unless version_environment[:environments].include?(system.environment)
version_environment[:environments] << cve.environment unless version_environment[:environments].include?(cve.environment)
version_environment[:next_version] ||= version.next_incremental_version
version_environment[:content_host_count] = systems.count
version_environment[:content_host_count] ||= 0
version_environment[:content_host_count] += systems.where(:content_view_id => cve.content_view).where(:environment_id => cve.environment).count

if version.content_view.composite?
version_environment[:components] = version.components_needing_errata(@errata)
else
version_environment[:components] = nil
end

version_environments[version] = OpenStruct.new(version_environment)
end

Expand Down
10 changes: 8 additions & 2 deletions app/lib/actions/katello/content_view/incremental_updates.rb
Expand Up @@ -23,9 +23,15 @@ def plan(version_environments, content, dep_solve, propagate_composites, systems
sequence do
concurrence do
version_environments.each do |version_environment|
action = plan_action(ContentViewVersion::IncrementalUpdate, version_environment[:content_view_version],
version = version_environment[:content_view_version]
if version.content_view.composite?
fail _("Cannot perform an incremental update on a Composite Content View Version (%{name} version version %{version}") %
{:name => version.content_view.name, :version => version.version}
end

action = plan_action(ContentViewVersion::IncrementalUpdate, version,
version_environment[:environments], :resolve_dependencies => dep_solve, :content => content, :description => description)
old_new_version_map[version_environment[:content_view_version]] = action.new_content_view_version
old_new_version_map[version] = action.new_content_view_version
output_for_version_ids << {:version_id => action.new_content_view_version.id, :output => action.output}
end
end
Expand Down
5 changes: 5 additions & 0 deletions app/models/katello/content_view_environment.rb
Expand Up @@ -32,6 +32,11 @@ class ContentViewEnvironment < Katello::Model

scope :non_default, joins(:content_view).where("katello_content_views.default" => false)

def self.for_systems(systems)
joins("INNER JOIN #{System.table_name} on #{System.table_name}.environment_id = #{ContentViewEnvironment.table_name}.environment_id").
where("#{System.table_name}.content_view_id = #{ContentViewEnvironment.table_name}.content_view_id").where("#{System.table_name}.id" => systems)
end

# retrieve the owning environment for this content view environment.
def owner
self.environment
Expand Down
7 changes: 7 additions & 0 deletions app/models/katello/content_view_version.rb
Expand Up @@ -174,6 +174,13 @@ def puppet_modules
end
end

def components_needing_errata(errata)
component_repos = Repository.where(:content_view_version_id => self.components)
library_repos = Repository.where(:id => component_repos.pluck(:library_instance_id)).with_errata(errata)
component_repos -= component_repos.with_errata(errata) #find component repos without the errata
component_repos.select { |repo| library_repos.include?(repo.library_instance) }.map(&:content_view_version).uniq
end

def packages
repositories.archived.flat_map(&:packages)
end
Expand Down
4 changes: 4 additions & 0 deletions app/models/katello/repository.rb
Expand Up @@ -302,6 +302,10 @@ def packages_without_errata
packages_without_filenames(filenames)
end

def self.with_errata(errata)
joins(:repository_errata).where("#{Katello::RepositoryErratum.table_name}.erratum_id" => errata)
end

def errata_filenames
Katello::ErratumPackage.joins(:erratum => :repository_errata).
where("#{RepositoryErratum.table_name}.repository_id" => self.id).pluck(:filename)
Expand Down
Expand Up @@ -13,3 +13,9 @@ child :environments => :environments do
end

attributes :next_version, :content_host_count

child :components => :components do
attributes :name, :id
attributes :next_incremental_version => :next_version
attributes :content_view_id
end
Expand Up @@ -33,8 +33,22 @@ angular.module('Bastion.errata').controller('ApplyErrataController',
$scope.errorMessages = [];
$scope.applyingErrata = false;

$scope.hasComposites = function (updates) {
if (updates) {
var composite = _.find(updates, function (update) {
return update.components;
});
return composite;
}
return false;
};

$scope.toggleComponents = function (update) {
update.componentsVisible = !update.componentsVisible;
};

incrementalUpdate = function () {
var success, error, params = {};
var success, error, params = {}, cvIdEnvIds = {};

$scope.applyingErrata = true;

Expand All @@ -46,13 +60,31 @@ angular.module('Bastion.errata').controller('ApplyErrataController',
params['propagate_to_composites'] = true;
params['resolve_dependencies'] = true;

//get a list of unique content view verion ids with their environments
angular.forEach($scope.updates, function (update) {
var incrementalUpdate = {
'content_view_version_id': update['content_view_version'].id,
'environment_ids': _.pluck(update.environments, 'id')
};
var versionId = update['content_view_version'].id;

if (update.components) {
angular.forEach(_.pluck(update.components, 'id'), function (componentId) {
if (cvIdEnvIds[componentId] === undefined) {
cvIdEnvIds[componentId] = [];
}
});
}
else {

if (cvIdEnvIds[versionId] === undefined) {
cvIdEnvIds[versionId] = [];
}
cvIdEnvIds[versionId] = _.uniq(cvIdEnvIds[versionId].concat(_.pluck(update.environments, 'id')));
}
});

params['content_view_version_environments'].push(incrementalUpdate);
angular.forEach(cvIdEnvIds, function (envIds, cvId) {
params['content_view_version_environments'].push({
'content_view_version_id': parseInt(cvId, 10),
'environment_ids': envIds
});
});

if ($scope.applyErrata) {
Expand Down
Expand Up @@ -35,7 +35,7 @@ <h3 ng-show="errata" translate>Apply {{ errata.errata_id }}</h3>
will be created which will make this Errata Installable in the host's Environment. This new version will replace the current version in your host's Lifecycle
Environment. To install these errata immediately on hosts after publishing check the box below.
</p>

<table class="table table-striped table-bordered">
<thead>
<tr>
Expand All @@ -49,9 +49,33 @@ <h3 ng-show="errata" translate>Apply {{ errata.errata_id }}</h3>
<tbody>
<tr ng-repeat="update in updates">
<td>
<a ng-href="/content_views/{{ update.content_view_version.content_view.id }}/versions">{{ update.content_view_version.content_view.name }}</a>
<div>
<i class="fa fa-chevron-down" ng-show="update.componentsVisible && update.components" ng-click="toggleComponents(update)"></i>
<i class="fa fa-chevron-right" ng-hide="update.componentsVisible && update.components" ng-click="toggleComponents(update)"></i>
<a ng-href="/content_views/{{ update.content_view_version.content_view.id }}/versions/{{update.content_view_version.id}}">{{ update.content_view_version.content_view.name }}</a> <span ng-show="{{update.components}}">*</span>
</div>
<div ng-show="update.componentsVisible">
<span translate>
Components:
</span>
<ul>
<li ng-repeat="component in update.components" class="row">
<a class="col-sm-offset-1" ng-href="/content_views/{{ component.content_view_id }}/versions/{{component.id}}">{{ component.name }}</a>
</li>
</ul>
</div>
</td>
<td>
<div>
{{ update.next_version }}
</div>
<div ng-show="update.componentsVisible">
&nbsp;
<ul>
<li ng-repeat="component in update.components">{{ component.next_version }}</li>
</ul>
</div>
</td>
<td>{{ update.next_version }}</td>
<td>
<span ng-repeat="environment in update.environments">
<a ng-href="/lifecycle_environments/{{ environment.id }}/details">
Expand All @@ -69,6 +93,11 @@ <h3 ng-show="errata" translate>Apply {{ errata.errata_id }}</h3>
</section>

<form name="errataConfirm" role="form" ng-submit="confirmApply()">
<div ng-show="updates && hasComposites(updates)">
<span translate>
* These marked Content View Versions are from Composite Content Views. Their components needing updating are listed underneath.
</span>
</div>
<div class="checkbox" ng-show="updates">
<label>
<input name="applyErrata" ng-model="applyErrata" type="checkbox"/>
Expand Down
Expand Up @@ -167,6 +167,7 @@ describe('Controller: ApplyErrataController', function() {

expect($scope.transitionTo).toHaveBeenCalledWith('errata.tasks.details', {taskId: 1});
expect($scope.errorMessages.length).toBe(0);
expect($scope.hasComposites($scope.updates)).toBeFalsy();
});

it("and fail", function () {
Expand All @@ -185,5 +186,87 @@ describe('Controller: ApplyErrataController', function() {
$scope.confirmApply();
});
});

describe("if an incremental update is needed with composites", function () {
beforeEach(function () {
expectedParams = {
'add_content': {
'errata_ids': [10]
},
'content_view_version_environments': [{
'content_view_version_id': 5,
'environment_ids': []
}],
'propagate_to_composites': true,
'resolve_dependencies': true
};

$scope.updates = [{
'content_view_version': {id: 1},
environments: [{id: 2}],
components: [{id: 5}]
}];

spyOn(ContentViewVersion, 'incrementalUpdate').andCallThrough();
});

afterEach(function () {
expect(ContentViewVersion.incrementalUpdate).toHaveBeenCalledWith(expectedParams, jasmine.any(Function),
jasmine.any(Function));
});

it("and succeed", function () {
spyOn($scope, 'transitionTo');

$scope.confirmApply();

expect($scope.transitionTo).toHaveBeenCalledWith('errata.tasks.details', {taskId: 1});
expect($scope.errorMessages.length).toBe(0);
expect($scope.hasComposites($scope.updates)).toBeTruthy();
});
});

describe("if an incremental update is needed with composites and component", function () {
beforeEach(function () {
expectedParams = {
'add_content': {
'errata_ids': [10]
},
'content_view_version_environments': [{
'content_view_version_id': 5,
'environment_ids': [99]
}],
'propagate_to_composites': true,
'resolve_dependencies': true
};

$scope.updates = [{
'content_view_version': {id: 1},
environments: [{id: 2}],
components: [{id: 5}]
},{
'content_view_version': {id: 5},
environments: [{id: 99}],
components: undefined
}];

spyOn(ContentViewVersion, 'incrementalUpdate').andCallThrough();
});

afterEach(function () {
expect(ContentViewVersion.incrementalUpdate).toHaveBeenCalledWith(expectedParams, jasmine.any(Function),
jasmine.any(Function));
});

it("and succeed", function () {
spyOn($scope, 'transitionTo');

$scope.confirmApply();

expect($scope.transitionTo).toHaveBeenCalledWith('errata.tasks.details', {taskId: 1});
expect($scope.errorMessages.length).toBe(0);
expect($scope.hasComposites($scope.updates)).toBeTruthy();
});
});
});
});
@@ -0,0 +1,6 @@

component_1:
component_version_id: <%= ActiveRecord::Fixtures.identify(:library_view_version_1) %>
composite_version_id: <%= ActiveRecord::Fixtures.identify(:composite_view_version_1) %>
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
13 changes: 13 additions & 0 deletions test/fixtures/models/katello_repositories.yml
Expand Up @@ -259,3 +259,16 @@ busybox_view2:
gpg_key_id: <%= ActiveRecord::Fixtures.identify(:fedora_gpg_key) %>
content_view_version_id: <%= ActiveRecord::Fixtures.identify(:library_view_version_2) %>

rhel_6_x86_64_composite_view_version_1:
name: RHEL 6 x86_64
pulp_id: 8
content_id: 1
major: 6
minor: 6Server
content_type: yum
label: rhel_6_x86_64_label_composite_view_version_1
relative_path: '/ACME_Corporation/library/composite/rhel_6_label'
environment_id: <%= ActiveRecord::Fixtures.identify(:library) %>
product_id: <%= ActiveRecord::Fixtures.identify(:redhat) %>
gpg_key_id: <%= ActiveRecord::Fixtures.identify(:fedora_gpg_key) %>
content_view_version_id: <%= ActiveRecord::Fixtures.identify(:composite_view_version_1) %>
3 changes: 2 additions & 1 deletion test/models/authorization/content_view_authorization_test.rb
Expand Up @@ -114,13 +114,14 @@ def test_readable_products_with_ids
end

def test_readable_products_with_search
prod = Katello::Repository.find(katello_repositories(:rhel_6_x86_64_composite_view_version_1)).product
view = katello_content_views(:library_view)
view2 = katello_content_views(:composite_view)
setup_current_user_with_permissions(:name => "view_content_views",
:search => "name=\"#{view.name}\"")

assert_empty(ContentView.readable_products - view.products)
assert_empty(ContentView.readable_products(view2.products.pluck(:id)))
assert_equal ContentView.readable_products(view2.products.pluck(:id)), [prod]
end
end
end
33 changes: 33 additions & 0 deletions test/models/content_view_environment_test.rb
@@ -0,0 +1,33 @@
#
# 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.

require 'katello_test_helper'

module Katello
class ContentViewEnvironmentTest < ActiveSupport::TestCase
def self.before_suite
#models = ["Organization", "KTEnvironment", "User", "ContentView",
# "ContentViewEnvironment", "ContentViewPuppetEnvironment", "ContentViewVersion"]
#disable_glue_layers(["Candlepin", "Pulp", "ElasticSearch"], models, true)
end

def setup
User.current = User.find(users(:admin))
@system = Katello::System.find(katello_systems(:simple_server))
end

def test_for_systems
cve = @system.content_view.content_view_environment(@system.environment)
assert_include ContentViewEnvironment.for_systems(@system), cve
end
end
end
6 changes: 6 additions & 0 deletions test/models/content_view_version_test.rb
Expand Up @@ -108,4 +108,10 @@ def test_component_non_composite
@cvv.components = [@composite_version]
end
end

def test_components_needing_errata
errata = Erratum.find(katello_errata(:security))
component = @composite_version.components.first
assert_include @composite_version.components_needing_errata([errata]), component
end
end

0 comments on commit 546cb7e

Please sign in to comment.