-
Notifications
You must be signed in to change notification settings - Fork 167
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
create content_view_rollback role #1217
Open
bmarlow
wants to merge
3
commits into
theforeman:develop
Choose a base branch
from
bmarlow:content_view_rollback
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+173
−0
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
theforeman.foreman.content_view_rollback | ||
========= | ||
|
||
A role for automating the rollback of Content-Views. | ||
|
||
Requirements | ||
------------ | ||
|
||
This role requires the theforeman.foreman module collection. | ||
|
||
Role Variables | ||
-------------- | ||
|
||
The primary dictionary is the organizations dictionary, which is formatted as such: | ||
``` | ||
organizations: | ||
org1: | ||
lifecycle_environments: | ||
- "Dev" | ||
- "QA" | ||
- "Prod" | ||
content_views: | ||
- "content-view1" | ||
- "content-view2" | ||
org2: | ||
lifecycle_environments: | ||
- "Dev2" | ||
- "QA2" | ||
- "Prod2" | ||
content_views: | ||
- "content-view3" | ||
- "content-view4" | ||
``` | ||
|
||
This can run against multiple organizations/lifecycle_environments/content-views or selected subsets. | ||
|
||
For example, if the previously mentioned dictionary describes *ALL* of my Foreman environment, but I only want to rollback the 'Prod' lifecycle_environment in the content-view 'content-view1' in organization 'org', my dictionary would look like this: | ||
``` | ||
organizations: | ||
org1: | ||
lifecycle_environments: | ||
- "Prod" | ||
content_views: | ||
- "content-view1" | ||
``` | ||
Items not described in the inventory will not be affected. | ||
|
||
Dependencies | ||
------------ | ||
|
||
You need a Foreman user with admin access to the Organizations, Lifecycle_Environments, and Content_Views you wish to interact with. | ||
|
||
By default, the role will require a valid SSL certificate installed on your Foreman server that the ansible client can trace trust to. To disable that update the 'FOREMAN_VALIDATE_CERTS' variable in defaults/main.yml. | ||
|
||
For example, to disable certificate checking you would update the variable as such: | ||
``` | ||
FOREMAN_VALIDATE_CERTS: false | ||
``` | ||
|
||
Example Playbook | ||
---------------- | ||
|
||
The role can be instantiated quite simply, all of the decision making is handled by the variables previously set: | ||
|
||
``` | ||
--- | ||
- name: "Run the content_view_rollback Role" | ||
hosts: all | ||
tasks: | ||
- name: "Run the content_view_rollback Role" | ||
include_role: | ||
name: theforeman.foreman.content_view_rollback | ||
``` | ||
For example: | ||
|
||
Rolling back Lifecycle Environments inside their respective Content-Views to the previous version: | ||
``` | ||
organizations: | ||
org1: | ||
lifecycle_environments: | ||
- "Dev" | ||
- "QA" | ||
- "Prod" | ||
content_views: | ||
- "content-view1" | ||
- "content-view2" | ||
``` | ||
|
||
The role would take the Dev, QA and Prod Lifecycle Environments to Content-View version N-1. If, prior to role runtime, the versions were: Prod=10, QA=11, and Dev=12, the result at the end of the run would be: Prod=9, QA=10, and Dev=11. If that Content-View version does not exist it will select the next lowest Content-View version. If there are none lower, it will exit with a message saying such. | ||
|
||
To perform actions across multiple Organizations: | ||
``` | ||
organizations: | ||
org1: | ||
lifecycle_environments: | ||
- "Dev" | ||
- "QA" | ||
- "Prod" | ||
content_views: | ||
- "content-view1" | ||
- "content-view2" | ||
org2: | ||
lifecycle_environments: | ||
- "LCE1" | ||
- "LCE2" | ||
content_views: | ||
- "org2_content-view" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--- | ||
# defaults file for content_view_promotion_rollback_publish | ||
FOREMAN_VALIDATE_CERTS: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- name: "Rollback Content-Views" | ||
include_tasks: rollback.yml | ||
loop: "{{ organization.value.content_views }}" | ||
loop_control: | ||
loop_var: content_view |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
- name: "Run Content-View Role" | ||
include_tasks: content-view.yml | ||
with_dict: "{{ organizations }}" | ||
loop_control: | ||
loop_var: organization |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
--- | ||
# get data on the current content-view | ||
- name: "Gather Data For Current Content-View From Foreman" | ||
theforeman.foreman.resource_info: | ||
username: "{{ foreman_user }}" | ||
password: "{{ foreman_password }}" | ||
server_url: "{{ foreman_server_url }}" | ||
organization: "{{ organization.key }}" | ||
resource: content_views | ||
search: name = "{{ content_view }}" | ||
validate_certs: false | ||
register: content_view_data | ||
|
||
# get data on the current content-view version | ||
- name: "Gather Data For Current Content-View Versions From Foreman" | ||
theforeman.foreman.resource_info: | ||
username: "{{ foreman_user }}" | ||
password: "{{ foreman_password }}" | ||
server_url: "{{ foreman_server_url }}" | ||
organization: "{{ organization.key }}" | ||
resource: content_view_versions | ||
params: | ||
content_view_id: "{{ content_view_data.resources[0].id }}" | ||
register: version_information | ||
|
||
# creates a dictionary with data formatted as such {'Prod':'11.0'} | ||
- name: "Build Dictionary With Lifecycle Envrionment And Version Number" | ||
set_fact: | ||
environments: "{{ environments | default({}) | combine ({item[1].name : item[0].name.split()[-1]}) }}" | ||
with_subelements: | ||
- "{{ version_information.resources }}" | ||
- environments | ||
|
||
# create list of content-view versions | ||
- name: "Build List of All Versions of Content-View" | ||
set_fact: | ||
cv_versions: "{{ cv_versions | default([]) + [item.major] }}" | ||
with_items: "{{ version_information.resources }}" | ||
|
||
# set the highest version to zero so that we don't use previous Content-View settings | ||
- name: "Set Lowest Version to 0" | ||
set_fact: | ||
lowest_version: 0 | ||
|
||
# set highest number | ||
- name: "Set the Lowest Version of the Content-View Currently Available" | ||
set_fact: | ||
lowest_version: "{{ cv_versions | min }}" | ||
|
||
# add one to each of the version numbers | ||
- name: "Update Facts With Incremented Content-View Version Numbers" | ||
set_fact: | ||
new_environments: "{{ new_environments | default({}) | combine({item.key: item.value|int - 1.0 }) }}" | ||
with_dict: "{{ environments }}" | ||
|
||
# check if each of the N-1 versions exist | ||
- name: "Check to make sure previous version exists" | ||
set_fact: | ||
non_environments: "{{ non_environments | default({}) | combine({item.key: item.value }) }}" | ||
with_dict: "{{ new_environments }}" | ||
when: item.value not in cv_versions | ||
|
||
- name: "Check for next closest, lower version" | ||
include_tasks: version.yml | ||
with_dict: "{{ non_environments }}" | ||
loop_control: | ||
loop_var: version | ||
|
||
# check if each of the N-1 versions exist | ||
- name: "Check to make sure previous version exists" | ||
fail: | ||
msg: "There is no version lower than {{ item.value }} to roll back to for Content-View {{ item.key }}. Stopping execution." | ||
with_dict: "{{ new_environments }}" | ||
when: item.value not in cv_versions | ||
|
||
# only promote environments defined in the vars | ||
- name: "Rollback Environments to Version N-1" | ||
theforeman.foreman.content_view_version: | ||
username: "{{ foreman_user }}" | ||
password: "{{ foreman_password }}" | ||
server_url: "{{ foreman_server_url }}" | ||
organization: "{{ organization.key }}" | ||
content_view: "{{ content_view }}" | ||
# dictionaries aren't ordered and Foreman doesn't want you promoting things out of order | ||
# but we're promoting them all so we just override that behavior | ||
force_promote: true | ||
lifecycle_environments: "{{ item.key }}" | ||
version: "{{ item.value }}" | ||
with_dict: "{{ new_environments }}" | ||
when: item.key in organization.value.lifecycle_environments |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
# reset the var value to the next lowest value | ||
# reversing the list and iterating downwards until first match would be more efficient | ||
- name: "Get closest lower version" | ||
set_fact: | ||
new_environments: "{{ new_environments | combine({version.key: item}) }}" | ||
with_items: "{{ cv_versions | sort | list }}" | ||
when: item | int < version.value | int | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Maybe this can be turned into a filter plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which part do you think would lend itself best to being a filter plugin?
My main concern here, is that we are pretty much handling this with 3 lines right now, and (at least after my cursory glance) adding a filter plugin would also require more code and perhaps make this a bit more confusing.
However, filters for something like 'get_next_lowest' integer in a list and 'get_next_highest' integer in a list might be good ideas for core contributions.
If that's of interest I can always make a PR over there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking exactly about that kind of arithmetic. It was my first thought when reading the task name, and was reinforced by seeing set_fact. I'm fine if we say, that's a task for another PR on a another day.