Nir Soffer has posted comments on this change.

Change subject: fcp: Deactivate vdsm logical volumes
......................................................................


Patch Set 4:

(20 comments)

....................................................
Commit Message
Line 13: corruption sooner or later, when a vm is trying to write to logical
Line 14: volume with stale metadata.
Line 15: 
Line 16: This patch adds new vdsm-tool lvm-deactivate-lvs command, deactivating
Line 17: vdsm active logical volumes. The command is invoked during boot as part
Not finished yet.
Line 18: of vdsmd pre-start. If vdsmd was disabled during boot, or an older vdsm
Line 19: version was started during boot, the command is invoked in the first
Line 20: time vdsmd is started.
Line 21: 


Line 23: running vms, the lvm-deactivate-lvs command does not deactivate open
Line 24: devices.
Line 25: 
Line 26: We chose this solution because it is compatible with all upstream and
Line 27: downstream supported versions, easy to implement, and does not require
Done
Line 28: changes in vdsm delicate runtime.
Line 29: 
Line 30: We considered several other solutions:
Line 31: - Using volume_list lvm configuration: By adding system vgs to this


Line 38: - Modifying system init scripts: We rejected this because it is not
Line 39:   their responsibility to activate only certain vgs, and touching them 
is
Line 40:   last resort.
Line 41: 
Line 42: This patch should be easy to backport to RHEV 3.2, invoking the new
I''l replace with ovirt-3.2.
Line 43: vdsm-tool command from the legacy vdsmd.init script instead of 
pre-start
Line 44: available only in ovirt 3.3.
Line 45: 
Line 46: Change-Id: I8f72a68ad09566ba222aa45448c78d1577c40d21


....................................................
File lib/vdsm/tool/lvm_deactivate_lvs.py
Line 18: #
Line 19: 
Line 20: """
Line 21: When using FC storage, physical volumes are connected during boot, and 
vdsm
Line 22: logical volumes are auto-activated during boot. These volumes do not 
pick
Commit message does not replace module documentation. To get the commit message 
you must search through history, reading multiple commit messages. The reader 
needs this info here.
Line 23: changes done by the SPM on the storage, which may lead to data 
corruption
Line 24: sooner or later, when a vm is trying to write to logical volume with 
stale
Line 25: metadata.
Line 26: 


Line 33: import sys
Line 34: 
Line 35: from vdsm import tool
Line 36: from vdsm import utils
Line 37: from vdsm import constants
I'll use absolute import.
Line 38: 
Line 39: NAME = 'lvm-deactivate-lvs'
Line 40: RUN_FILE = os.path.join(constants.P_VDSM_RUN, NAME)
Line 41: 


Line 38: 
Line 39: NAME = 'lvm-deactivate-lvs'
Line 40: RUN_FILE = os.path.join(constants.P_VDSM_RUN, NAME)
Line 41: 
Line 42: LVM_SEPARATOR = "|"
Module constant, see vdsm.storage.lvm.
Line 43: 
Line 44: # Tags used to detect vdsm FC vgs
Line 45: VG_SD_TAG = "RHAT_storage_domain"
Line 46: VG_FCP_TAG = "MDT_TYPE=FCP"


Line 48: 
Line 49: class Error(Exception):
Line 50:     """
Line 51:     Raised for expected errors in this module.
Line 52:     """
pass is redundant when you have a docstring.

This is *lvm_deactivate_lvs.Error* - meaning error in this module which should 
be treated differently then other errors. Used here to log the error and return 
a non-zero return code on expected failures.

RuntimeError is a library error and should not be used in your code unless you 
want to make it harder for the caller to tell a real RuntimeError and your 
module sepcific errors.

See http://docs.python.org/2.6/library/exceptions.html#exceptions.RuntimeError
Line 53: 
Line 54: 
Line 55: @tool.expose(NAME)
Line 56: def main(*args, **kwargs):


Line 51:     Raised for expected errors in this module.
Line 52:     """
Line 53: 
Line 54: 
Line 55: @tool.expose(NAME)
Why not a constant?  And why not lvm-deactivate-lvs, like libvirt-configure?
Line 56: def main(*args, **kwargs):
Line 57:     """
Line 58:     Deactivates unused vdsm volume lvs.
Line 59:     """


Line 52:     """
Line 53: 
Line 54: 
Line 55: @tool.expose(NAME)
Line 56: def main(*args, **kwargs):
I took nwfilter as example - isn't the expose is enough to give info the the 
tool?
Line 57:     """
Line 58:     Deactivates unused vdsm volume lvs.
Line 59:     """
Line 60:     try:


Line 56: def main(*args, **kwargs):
Line 57:     """
Line 58:     Deactivates unused vdsm volume lvs.
Line 59:     """
Line 60:     try:
Entire function is covered so I can throw Error everywhere in this module when 
an expected failure is detected. This does not effect other exceptions anyway.

For example, was_run does not throw an Error today, but if we start throwing it 
in the future, we don't have to change the main logic.
Line 61:         if was_run():
Line 62:             log("already run")
Line 63:             return 0
Line 64:         set_was_run()


Line 71:             log("no vgs found")
Line 72:         return 0
Line 73:     except Error as e:
Line 74:         log(e)
Line 75:         return 1
I took sanlock.py as example and it does return either 0 or 1 - are you sure 
about it?
Line 76: 
Line 77: 
Line 78: def log(msg):
Line 79:     sys.stderr.write("%s: %s\n" % (NAME, msg))


Line 74:         log(e)
Line 75:         return 1
Line 76: 
Line 77: 
Line 78: def log(msg):
Do you suggest to duplicate this logging code everywhere?

Most of the log calls here are for debugging - we probably need a way to 
disable them in production. Maybe use logging module?
Line 79:     sys.stderr.write("%s: %s\n" % (NAME, msg))
Line 80: 
Line 81: 
Line 82: def was_run():


Line 79:     sys.stderr.write("%s: %s\n" % (NAME, msg))
Line 80: 
Line 81: 
Line 82: def was_run():
Line 83:     return os.path.exists(RUN_FILE)
I prefer self explaining code to comments. Aren't these functions clear?
Line 84: 
Line 85: 
Line 86: def set_was_run():
Line 87:     with open(RUN_FILE, 'w'):


Line 83:     return os.path.exists(RUN_FILE)
Line 84: 
Line 85: 
Line 86: def set_was_run():
Line 87:     with open(RUN_FILE, 'w'):
This creates RUN_FILE - how os.acess is related?
Line 88:         pass
Line 89: 
Line 90: 
Line 91: def find_vdsm_vgs():


Line 87:     with open(RUN_FILE, 'w'):
Line 88:         pass
Line 89: 
Line 90: 
Line 91: def find_vdsm_vgs():
Everything here is private except main - do you want to prefix everthing with _?
Line 92:     rc, out, err = lvm("vgs", "--noheading", "--separator", 
LVM_SEPARATOR,
Line 93:                        "-o", "vg_name,tags")
Line 94:     if rc != 0:
Line 95:         raise Error("Error finding vgs: %s" % err)


Line 94:     if rc != 0:
Line 95:         raise Error("Error finding vgs: %s" % err)
Line 96:     for line in out.splitlines():
Line 97:         vg, tags = line.split(LVM_SEPARATOR, 1)
Line 98:         if is_vdsm_vg(tags):
Same reason is_active_lv and is_open_lv are used.
Line 99:             yield vg
Line 100: 
Line 101: 
Line 102: def find_lvs(vg):


Line 95:         raise Error("Error finding vgs: %s" % err)
Line 96:     for line in out.splitlines():
Line 97:         vg, tags = line.split(LVM_SEPARATOR, 1)
Line 98:         if is_vdsm_vg(tags):
Line 99:             yield vg
Yielding it cleaner here and allow both iterative use for the caller, and if 
needed, the caller can collect the value using list(find_vgs) as needed. More 
options, less code.
Line 100: 
Line 101: 
Line 102: def find_lvs(vg):
Line 103:     rc, out, err = lvm("lvs", "--noheading", "--separator", 
LVM_SEPARATOR,


Line 110:             continue
Line 111:         if is_open_lv(attr):
Line 112:             log("Warning: skipping %s/%s: device is open" % (vg, lv))
Line 113:             continue
Line 114:         yield lv
Same reason
Line 115: 
Line 116: 
Line 117: def is_vdsm_vg(vg_tags):
Line 118:     tags = set(vg_tags.split(","))


Line 120: 
Line 121: 
Line 122: def is_active_lv(lv_attr):
Line 123:     # -wi-ao---
Line 124:     return lv_attr[4] == "a"
What do you think is more readable:

    if not is_active_lv(attr):
        continue

    if attr[4] == "-":  # is not active (-wi------)
        continue

The extra function call cost nothing, the readability improved.

I can replace this with is_inactive, as this is what we look for:

     if is_inactive(attr):
         continue
Line 125: 
Line 126: 
Line 127: def is_open_lv(lv_attr):
Line 128:     # -wi-ao---


Line 136:     if rc != 0:
Line 137:         raise Error("Error deactivating %s: %s" % (lv_path, err))
Line 138: 
Line 139: 
Line 140: def lvm(*args):
I'll call it run_lvm as this is lvm specific.
Line 141:     cmd = [constants.EXT_LVM]
Line 142:     cmd.extend(args)


-- 
To view, visit http://gerrit.ovirt.org/20720
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: comment
Gerrit-Change-Id: I8f72a68ad09566ba222aa45448c78d1577c40d21
Gerrit-PatchSet: 4
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsof...@redhat.com>
Gerrit-Reviewer: Allon Mureinik <amure...@redhat.com>
Gerrit-Reviewer: Alon Bar-Lev <alo...@redhat.com>
Gerrit-Reviewer: Ayal Baron <aba...@redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <dan...@redhat.com>
Gerrit-Reviewer: Federico Simoncelli <fsimo...@redhat.com>
Gerrit-Reviewer: Nir Soffer <nsof...@redhat.com>
Gerrit-Reviewer: Yaniv Bronhaim <ybron...@redhat.com>
Gerrit-Reviewer: oVirt Jenkins CI Server
Gerrit-HasComments: Yes
_______________________________________________
vdsm-patches mailing list
vdsm-patches@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to