This repository has been archived by the owner on Feb 9, 2022. It is now read-only.
Add additional python scripts to provide mapping validation and automatic scripts for generate_mapping failover and failback #38
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
be0d89c
Add bcolors class for better logging
9f26294
Add python scripts for generate_mapping
81f89d5
Add python validator script for mapping file
00edcb0
Add validation using SDK for existing entites
d01c6a5
Rename play to a general name
752538a
Support failover and failback scripts
976b72b
Introduce ovirt-dr
47c8008
Add documentation for scripts
2ff00d5
move generate_mapping file from tasks to files
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
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
File renamed without changes.
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,18 @@ | ||
#!/usr/bin/python | ||
|
||
|
||
class bcolors: | ||
HEADER = '\033[95m' | ||
OKBLUE = '\033[1;34m' | ||
OKGREEN = '\033[0;32m' | ||
WARNING = '\x1b[0;33m' | ||
FAIL = '\033[0;31m' | ||
ENDC = '\033[0m' | ||
|
||
def disable(self): | ||
self.HEADER = '' | ||
self.OKBLUE = '' | ||
self.OKGREEN = '' | ||
self.WARNING = '' | ||
self.FAIL = '' | ||
self.ENDC = '' |
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,20 @@ | ||
[generate_vars] | ||
site=http://engine.example.com/ovirt-engine/api | ||
username=admin@internal | ||
password= | ||
ca_file=/etc/pki/ovirt-engine/ca.pem | ||
output_file=/var/lib/ovirt-ansible-disaster-recovery/mapping_vars.yml | ||
ansible_play=../examples/dr_play.yml | ||
|
||
[validate_vars] | ||
var_file=/var/lib/ovirt-ansible-disaster-recovery/mapping_vars.yml | ||
vault=../examples/ovirt_passwords.yml | ||
|
||
[failover_failback] | ||
dr_target_host=secondary | ||
dr_source_map=primary | ||
vault=passwords.yml | ||
var_file=/var/lib/ovirt-ansible-disaster-recovery/mapping_vars.yml | ||
ansible_play=../examples/dr_play.yml | ||
dr_report_file=/tmp/report.log | ||
|
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,250 @@ | ||
#!/usr/bin/python | ||
from bcolors import bcolors | ||
try: | ||
import configparser | ||
except ImportError: | ||
import ConfigParser as configparser | ||
import os.path | ||
import shlex | ||
import subprocess | ||
import sys | ||
|
||
from subprocess import call | ||
|
||
INFO = bcolors.OKGREEN | ||
INPUT = bcolors.OKGREEN | ||
WARN = bcolors.WARNING | ||
FAIL = bcolors.FAIL | ||
END = bcolors.ENDC | ||
PREFIX = "[Failback] " | ||
PLAY_DEF = "../examples/dr_play.yml" | ||
|
||
|
||
class FailBack(): | ||
|
||
def run(self, conf_file, log_file): | ||
print("\n%s%sStart failback operation...%s" | ||
% (INFO, | ||
PREFIX, | ||
END)) | ||
dr_tag = "fail_back" | ||
dr_clean_tag = "clean_engine" | ||
target_host, source_map, var_file, vault, ansible_play = \ | ||
self._init_vars(conf_file) | ||
print("\n%s%starget_host: %s \n" | ||
"%ssource_map: %s \n" | ||
"%svar_file: %s \n" | ||
"%svault: %s \n" | ||
"%sansible_play: %s%s \n" | ||
% (INFO, | ||
PREFIX, | ||
target_host, | ||
PREFIX, | ||
source_map, | ||
PREFIX, | ||
var_file, | ||
PREFIX, | ||
vault, | ||
PREFIX, | ||
ansible_play, | ||
END)) | ||
|
||
cmd = [] | ||
cmd.append("ansible-playbook") | ||
cmd.append(ansible_play) | ||
cmd.append("-t") | ||
cmd.append(dr_clean_tag) | ||
cmd.append("-e") | ||
cmd.append("@" + var_file) | ||
cmd.append("-e") | ||
cmd.append("@" + vault) | ||
cmd.append("-e") | ||
cmd.append(" dr_source_map=" + target_host) | ||
cmd.append("--vault-password-file") | ||
cmd.append("vault_secret.sh") | ||
cmd.append("-vvv") | ||
|
||
cmd_fb = [] | ||
cmd_fb.append("ansible-playbook") | ||
cmd_fb.append(ansible_play) | ||
cmd_fb.append("-t") | ||
cmd_fb.append(dr_tag) | ||
cmd_fb.append("-e") | ||
cmd_fb.append("@" + var_file) | ||
cmd_fb.append("-e") | ||
cmd_fb.append("@" + vault) | ||
cmd_fb.append("-e") | ||
cmd_fb.append(" dr_target_host=" + target_host + | ||
" dr_source_map=" + source_map) | ||
cmd_fb.append("--vault-password-file") | ||
cmd_fb.append("vault_secret.sh") | ||
cmd_fb.append("-vvv") | ||
|
||
# Setting vault password | ||
vault_pass = raw_input( | ||
INPUT + PREFIX + "Please enter the vault password: " + END) | ||
os.system("export vault_password=\"" + vault_pass + "\"") | ||
print("\n%s%sStarting cleanup process of setup '%s'" | ||
" for oVirt ansible disaster recovery%s" | ||
% (INFO, | ||
PREFIX, | ||
target_host, | ||
END)) | ||
with open(log_file, "w") as f: | ||
f.write("Executing cleanup command: %s" % ' '.join(map(str, cmd))) | ||
proc = subprocess.Popen(cmd, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE) | ||
for line in iter(proc.stdout.readline, ''): | ||
# TODO: since we dont want to have log and print the | ||
# progress in the stdout, we only filter the task names | ||
# We should find a better way to do so. | ||
if 'TASK [ovirt-ansible-disaster-recovery : ' in line: | ||
sys.stdout.write("\n" + line + "\n") | ||
f.write(line) | ||
|
||
print("\n%s%sFinished cleanup of setup '%s'" | ||
" for oVirt ansible disaster recovery%s" | ||
% (INFO, | ||
PREFIX, | ||
source_map, | ||
END)) | ||
|
||
print("\n%s%sStarting fail-back process to setup '%s'" | ||
" from setup '%s' for oVirt ansible disaster recovery" | ||
% (INFO, | ||
PREFIX, | ||
target_host, | ||
source_map)) | ||
|
||
f.write("Executing command %s" % ' '.join(map(str, cmd_fb))) | ||
proc_fb = subprocess.Popen(cmd_fb, | ||
stdout=subprocess.PIPE, | ||
stderr=subprocess.PIPE) | ||
for line in iter(proc_fb.stdout.readline, ''): | ||
# TODO: since we dont want to have log and print the | ||
# progress in the stdout, we only filter the task names | ||
# We should find a better way to do so. | ||
if 'TASK [ovirt-ansible-disaster-recovery :' in line: | ||
sys.stdout.write("\n" + line + "\n") | ||
if "[Failback Replication Sync]" in line: | ||
sys.stdout.write("\n" + INPUT + line + END) | ||
f.write(line) | ||
|
||
call(["cat", "report.log"]) | ||
print("\n%s%sFinished failback operation" | ||
" for oVirt ansible disaster recovery%s" | ||
% (INFO, | ||
PREFIX, | ||
END)) | ||
|
||
def _init_vars(self, conf_file): | ||
""" Declare constants """ | ||
_SECTION = "failover_failback" | ||
_TARGET = "dr_target_host" | ||
_SOURCE = "dr_source_map" | ||
_VAULT = "vault" | ||
_VAR_FILE = "var_file" | ||
_ANSIBLE_PLAY = 'ansible_play' | ||
setups = ['primary', 'secondary'] | ||
|
||
""" Declare varialbles """ | ||
target_host, source_map, vault, var_file, ansible_play = \ | ||
'', '', '', '', '' | ||
settings = configparser.ConfigParser() | ||
settings._interpolation = configparser.ExtendedInterpolation() | ||
settings.read(conf_file) | ||
if _SECTION not in settings.sections(): | ||
settings.add_section(_SECTION) | ||
if not settings.has_option(_SECTION, _TARGET): | ||
settings.set(_SECTION, _TARGET, '') | ||
if not settings.has_option(_SECTION, _SOURCE): | ||
settings.set(_SECTION, _SOURCE, '') | ||
if not settings.has_option(_SECTION, _VAULT): | ||
settings.set(_SECTION, _VAULT, '') | ||
if not settings.has_option(_SECTION, _VAR_FILE): | ||
settings.set(_SECTION, _VAR_FILE, '') | ||
if not settings.has_option(_SECTION, _ANSIBLE_PLAY): | ||
settings.set(_SECTION, _ANSIBLE_PLAY, '') | ||
# We fetch the source map as target host since in failback | ||
# we do the reverse operation. | ||
target_host = settings.get(_SECTION, _SOURCE, | ||
vars=DefaultOption(settings, | ||
_SECTION, | ||
source_map=None)) | ||
# We fetch the target host as target the source mapping for failback | ||
# since we do the reverse operation. | ||
source_map = settings.get(_SECTION, _TARGET, | ||
vars=DefaultOption(settings, | ||
_SECTION, | ||
target_host=None)) | ||
vault = settings.get(_SECTION, _VAULT, | ||
vars=DefaultOption(settings, | ||
_SECTION, | ||
vault=None)) | ||
var_file = settings.get(_SECTION, _VAR_FILE, | ||
vars=DefaultOption(settings, | ||
_SECTION, | ||
var_file=None)) | ||
ansible_play = settings.get(_SECTION, _ANSIBLE_PLAY, | ||
vars=DefaultOption(settings, | ||
_SECTION, | ||
ansible_play=None)) | ||
while target_host not in setups: | ||
target_host = raw_input( | ||
INPUT + PREFIX + "The target setup was not defined. " | ||
"Please provide the setup which it is failback to " | ||
"(primary or secondary): " + END) | ||
while source_map not in setups: | ||
source_map = raw_input( | ||
INPUT + PREFIX + "The source mapping was not defined. " | ||
"Please provide the source mapping " | ||
"(primary or secondary): " + END) | ||
while not os.path.isfile(var_file): | ||
var_file = raw_input("%s%svar file mapping '%s' does not exist. " | ||
"Please provide a valid mapping var file: %s" | ||
% (INPUT, | ||
PREFIX, | ||
var_file, | ||
END)) | ||
while not os.path.isfile(vault): | ||
vault = raw_input("%s%spassword file '%s' does not exist." | ||
"Please provide a valid password file:%s " | ||
% (INPUT, | ||
PREFIX, | ||
vault, | ||
END)) | ||
while (not ansible_play) or (not os.path.isfile(ansible_play)): | ||
ansible_play = raw_input("%s%sansible play '%s' " | ||
"is not initialized. " | ||
"Please provide the ansible play file " | ||
"to generate the mapping var file " | ||
"with ('%s'):%s " | ||
% (INPUT, | ||
PREFIX, | ||
str(ansible_play), | ||
PLAY_DEF, | ||
END) or PLAY_DEF) | ||
return (target_host, source_map, var_file, vault, ansible_play) | ||
|
||
|
||
class DefaultOption(dict): | ||
|
||
def __init__(self, config, section, **kv): | ||
self._config = config | ||
self._section = section | ||
dict.__init__(self, **kv) | ||
|
||
def items(self): | ||
_items = [] | ||
for option in self: | ||
if not self._config.has_option(self._section, option): | ||
_items.append((option, self[option])) | ||
else: | ||
value_in_config = self._config.get(self._section, option) | ||
_items.append((option, value_in_config)) | ||
return _items | ||
|
||
|
||
if __name__ == "__main__": | ||
FailBack().run('dr.conf', '/var/log/ovirt-dr/ovirt-dr.log') |
Oops, something went wrong.
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.
ovirt-dr
where is it installed in /usr/bin?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.
It should be somewhere 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'm not sure how to do that.
I prefer to do that on another patch so at least we will have this.
Meanwhile I've added a commit to this PR of spec file
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.
Ok, np, just that user must enter full path, which is different in galaxy and in RPM installation.
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.
Should I add this in the spec as well?