Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes #18964 - lifecycle environment container image name #7262

Merged
merged 1 commit into from May 21, 2018

Conversation

thomasmckay
Copy link
Member

@thomasmckay thomasmckay commented Mar 24, 2018

This feature allows a lifecycle environment to specify a image name pattern (erb) to
use instead of the default ($org-$prod-$env-$cv-$name).

For example "<%= organization.label %>/<%= docker_upstream_name %>"

The pattern, on the lifecycle UI details page, is used for container image repositories. These repos have a name and label but in pulp they also have a "registry name". This registry name is what users use when referencing the repo for "docker pull" or "skopeo copy".

Prior to this PR, the registry name was hard coded based on a combination of organization, product, content view, life cycle, and repo labels. This style of auto-naming remains if the life cycle pattern is left blank.

The pattern is ERB format. This allows a rich flexibility in the resulting names. In the simplest, and likely the most common, is to simply use the repository's original container image name as the pattern.

<%= repository.docker_upstream_name %>

It is important to remember that the results of running a repository through a life cycle's pattern must be unique across all repos in all orgs. Thus the same pattern should be reused in multiple life cycle's with care.

Variables available in ERB:

organization.name
organization.label
repository.name
repository.label
repository.docker_upstream_name
repository.url
content_view.label
content_view.name
content_view.version
product.name
product.label
lifecycle_environment.name
lifecycle_environment.label

@theforeman-bot
Copy link

Issues: #18964

@thomasmckay
Copy link
Member Author

thomasmckay commented Mar 24, 2018

@jlsherrill @parthaa @JacobCallahan - This feature will allow a 1:1 mirroring of a remote registry with the opportunity to keep the original image names (ie. openshift3/ose stays openshift3/ose for docker pull).

Open questions:

Should this be allowed for Library env? This would allow foreman to act as a constant mirror without user intervention, scheduled syncs would keep remote and foreman registries the same. (Note no mirror-on-sync feature in pulp @ipanova ;) )

Should I put a unique constraint on the registry_name_pattern? This will keep the chance of two repos having the same-named images. (I think that would violate pulp's rules but will confirm.)

When a registry_name_pattern is changed for a lifecycle, what is the best way to update all the component content view repos? How should this be presented to user?

How can I migrate all repos to retain their docker_upstream_name which was not being propogated to CVV repos? In a rake task or the migrate file?

@thomasmckay
Copy link
Member Author

P.S. @parthaa - I changed the validation to allow an upstream name without an upstream url. This would let images that are hammer or docker pushed to use the upstream name in their registry pattern. (ie. disconnected registry mirroring)

@ipanova
Copy link

ipanova commented Mar 26, 2018

@thomasmckay it is ok to have 2 different repos with same upstream_name, just make sure the registry_id is different because of https://pulp.plan.io/issues/3165

@thomasmckay
Copy link
Member Author

Current dilemma: A new attribute is added to lifecycle environment, registry_name_pattern. This pattern (ERB) will define the container_repository_name for all repos in that environment. At the moment, the repo attribute is only updated through a before_validation on save.

Here's how it should work: When the pattern attribute on an environment is updated, all the repos in that env need to have their name updated and propagated to pulp. All of the repos also need to be synced to capsules. (Ideally the sync would merely be for the repo attribute and not all content.)

@jlsherrill
Copy link
Member

@thomasmckay so what we would do normally is make the lifecycle env create controller action async (so that a task gets returned), and as part of that action update all the repos and propagate the changes to pulp.

However that already exists and is not async. What we could do is update the environment and then spawn a task to update all the docker repositories in the environment if the attribute changed. However the user still couldn't really track that easily to wait for it to finish and go use his docker repos. I assume that a desired feature?

@thomasmckay
Copy link
Member Author

@jlsherrill - What if on changing the env pattern the user had to explicitly kick off a resync of the component repos? I don't think this would be too burdensome since I don't see a pattern of frequent env changes being normal. Perhaps there is a new endpoint to env api to refresh repos that would return task?

end

#???? options content_type Katello::Repository::DOCKER_TYPE
def plan(env, options = {})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused method argument - options. If it's necessary, use _ or _options as an argument name to indicate that it won't be used.

update_params[:name] = params[:environment][:new_name] if params[:environment][:new_name]
@environment.update_attributes!(update_params)
if update_params[:registry_name_pattern]
task = sync_task(::Actions::Katello::Environment::PublishRepositories, @environment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless assignment to variable - task.

end

def run
env = ::Katello::KTEnvironment.find(input[:kt_environment][:id])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless assignment to variable - env.

env.repositories.each do |repository|
repository.save!
plan_action(::Actions::Katello::Repository::Update, repository, {})
plan_action(::Actions::Pulp::Repository::Refresh, repository)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jlsherrill @parthaa I'm just spamming actions here to try to get the the repo_registry_id to be updated in pulp. Any pointers of what to call to have that happen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I have this sorted out; will clean up code a bit since I think this double action is not needed.

concurrence do
env.repositories.each do |repository|
#repository.save!
plan_action(::Actions::Katello::Repository::Update, repository, {container_repository_name: repository.container_repository_name})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant curly braces around a hash parameter.

set_container_repository_name
valid?( :container_repository_name) ? container_repository_name : nil
ensure
content_repository_name = original_name

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/UselessAssignment: Useless assignment to variable - content_repository_name. Did you mean container_repository_name?

def validate_container_repository_name
original_name = container_repository_name
set_container_repository_name
valid?( :container_repository_name) ? container_repository_name : nil

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/SpaceInsideParens: Space inside parentheses detected.

@@ -757,6 +756,35 @@ def self.search_by_redhat(_key, operator, value)
end
end

def safe_render_container_name(pattern=nil)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/SpaceAroundEqualsInParameterDefault: Surrounding space missing in default value assignment.

end

def run
env = ::Katello::KTEnvironment.find(input[:kt_environment][:id])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/UselessAssignment: Useless assignment to variable - env.

concurrence do
repositories.each do |repository|
sequence do
plan_action(::Actions::Katello::Repository::Update, repository, {container_repository_name: repository.container_repository_name})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/BracesAroundHashParameters: Redundant curly braces around a hash parameter.

update_params[:name] = params[:environment][:new_name] if params[:environment][:new_name]
@environment.update_attributes!(update_params)
if update_params[:registry_name_pattern]
task = sync_task(::Actions::Katello::Environment::PublishRepositories, @environment, content_type: Katello::Repository::DOCKER_TYPE)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/UselessAssignment: Useless assignment to variable - task.

@thomasmckay
Copy link
Member Author

Added repo name verification on environment save. https://github.com/Katello/katello/pull/7262/files#diff-043f3f54ba4d6ae4333d75f582861bd3R1

<dd bst-edit-textarea="environment.registry_name_pattern"
on-save="save(environment)"
readonly="denied('edit_lifecycle_environments', environment)">
</dd>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@waldenraines - Is there a patternfly way to add some formatted help text to a field? I want to give brief description of valid formats but it should be formatted and not just a big unreadable string.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do this on create, but i couldn't find any examples of on edit :(

@@ -102,10 +104,19 @@ class Repository < Katello::Model
validates :product_id, :presence => true
validates :pulp_id, :presence => true, :uniqueness => true, :if => proc { |r| r.name.present? }
validates :checksum_type, :inclusion => {:in => CHECKSUM_TYPES}, :allow_blank => true
#???? refactor these into validator class, re-use in EnvironmentDockerRepositories validator
=begin

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/BlockComments: Do not use block comments.

@@ -102,10 +104,19 @@ class Repository < Katello::Model
validates :product_id, :presence => true
validates :pulp_id, :presence => true, :uniqueness => true, :if => proc { |r| r.name.present? }
validates :checksum_type, :inclusion => {:in => CHECKSUM_TYPES}, :allow_blank => true
#???? refactor these into validator class, re-use in EnvironmentDockerRepositories validator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/CommentIndentation: Incorrect indentation detected (column 4 instead of 0).

name = repository.safe_render_container_name(environment.registry_name_pattern)
#???? check pre-render name is same as post-render?

if !ContainerImageNameValidator.validate_name(name)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/NegatedIf: Favor unless over if for negative conditions.

end

def test_update_pattern_fail
original_label = @staging.label

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/UselessAssignment: Useless assignment to variable - original_label.

@@ -79,6 +105,49 @@ def test_update
assert_equal original_label, @staging.label
end

def test_update

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/DuplicateMethods: Method Katello::Api::V2::EnvironmentsControllerTest#test_update is defined at both test/controllers/api/v2/environments_controller_test.rb:93 and test/controllers/api/v2/environments_controller_test.rb:108.

update_params[:name] = params[:environment][:new_name] if params[:environment][:new_name]
@environment.update_attributes!(update_params)
if update_params[:registry_name_pattern]
#???? should task be returned? what would be returned when async_task not called?
#???? optional param to make this a sync_task?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i would return the task here. Technically the env is updated, its just further work that can be tracked

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jlsherrill Should I change this to call update_attributes! in the plan() of the task so that there is always a task to return? (Is plan() the right place to do that?

@thomasmckay thomasmckay changed the title [WIP] fixes #18964 - lifecycle environment container image name fixes #18964 - lifecycle environment container image name Apr 4, 2018
@theforeman-bot
Copy link

There were the following issues with the commit message:

  • commit message for 5c6ed65 is not wrapped at 72nd column

If you don't have a ticket number, please create an issue in Redmine.

More guidelines are available in Coding Standards or on the Foreman wiki.


This message was auto-generated by Foreman's prprocessor

@thomasmckay
Copy link
Member Author

State of the PR: All functionality works and there is robust checking of environment registry pattern to prevent duplicate repository names. Unit test writing continues but live usage testing by others would be appreciated.

@theforeman-bot
Copy link

There were the following issues with the commit message:

  • a05eb81 must be in the format fixes #redmine_number - brief description

If you don't have a ticket number, please create an issue in Redmine.

More guidelines are available in Coding Standards or on the Foreman wiki.


This message was auto-generated by Foreman's prprocessor

end

Katello::Repository.where(content_type: Katello::Repository::DOCKER_TYPE).each do |repository|
if !repositories.include?(repository) && names.include?(repository.container_repository_name)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jlsherrill - Updated this with original intention: Check all repos except for the current ones being processed (they're checked above) for name clashes.

Really struggling to write sensible tests.

@thomasmckay
Copy link
Member Author

Test I'd like to write in FactoryBot:

  1. CV 1 w/ repo A
  2. Add CV to LCE X
  3. Set LCE pattern "zzzzz" (static)
  4. Assert success
  5. CV 2 w/ repo A
  6. Add CV to LCE X
  7. Assert error

repo2_cv = build(:docker_repository, product: product, content_view_version: @organization.default_content_view.versions.first, library_instance_id: repo2_lib.id)
version2 = create(:katello_content_view_version, :content_view => view2, :repositories => [repo2_cv])


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/EmptyLines: Extra blank line detected.

@jlsherrill
Copy link
Member

[test katello]

@thomasmckay
Copy link
Member Author

[test katello]

@thomasmckay
Copy link
Member Author

Test written. Updated a few existing tests that had failed w/ the registry name unique constraint.
https://github.com/Katello/katello/pull/7262/files#diff-2b24dd48e0c60620fb05b0e0f6a83e66R19

@jlsherrill
Copy link
Member

[test katello]

@jlsherrill
Copy link
Member

Small rubocop error.

Also, i seem to be unable to repromote an existing cv that is already in dev, i get "Content View publish to environment dev will result in invalid container image name of member repositories", even though i'm promoting a cv thats already there.

@thomasmckay thomasmckay force-pushed the lifecycle-docker branch 2 times, most recently from bcbad9f to 3ba1341 Compare May 16, 2018 22:38
@thomasmckay
Copy link
Member Author

@jlsherrill - Removed the repos check and switched to rely on uniqueness validator for repos. I am less excited about this but I can't wrap my head around how I could correctly check all the names. :)

allowed_methods = {}
allowed_vars = {}
scope_variables = {repository: repository, organization: repository.organization, product: repository.product,
environment: repository.environment, contentview: repository.content_view_version.content_view}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mind making this 'content_view' instead of 'contentview'?

@thomasmckay
Copy link
Member Author

[test katello]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants