[PATCH] Code duplication removal
by Tony Asleson
Consolidate duplicate code to utils.
Signed-off-by: Tony Asleson <tasleson(a)redhat.com>
---
targetd/fs.py | 118 +++++++++++++++++++++++--------------------------------
targetd/main.py | 11 +-----
targetd/nfs.py | 20 +---------
targetd/utils.py | 27 ++++++++++++-
4 files changed, 78 insertions(+), 98 deletions(-)
diff --git a/targetd/fs.py b/targetd/fs.py
index a29479d..6b25649 100644
--- a/targetd/fs.py
+++ b/targetd/fs.py
@@ -18,9 +18,8 @@
import os
import time
-from subprocess import Popen, PIPE
-from main import TargetdError
from nfs import Nfs, Export
+from utils import invoke, TargetdError
# Notes:
@@ -80,24 +79,6 @@ def initialize(config_dict):
)
-def invoke(cmd, raise_exception=True):
- """
- Exec a command returning a tuple (exit code, stdout, stderr) and optionally
- throwing an exception on non-zero exit code.
- """
- c = Popen(cmd, stdout=PIPE, stderr=PIPE)
- out = c.communicate()
-
- if raise_exception:
- if c.returncode != 0:
- cmd_str = str(cmd)
- raise TargetdError(-303, 'Unexpected exit code "%s" %s, out= %s' %
- (cmd_str, str(c.returncode),
- str(out[0] + out[1])))
-
- return c.returncode, out[0], out[1]
-
-
def create_sub_volume(p):
if not os.path.exists(p):
invoke([fs_cmd, 'subvolume', 'create', p])
@@ -203,40 +184,49 @@ def fs_pools(req):
return results
+def _invoke_retries(command, throw_exception):
+ # TODO take out this loop, used to handle bug in btrfs
+ # ERROR: Failed to lookup path for root 0 - No such file or directory
+
+ for i in range(0, 5):
+ result, out, err = invoke(command, False)
+ if result == 0:
+ return result, out, err
+ elif result == 19:
+ time.sleep(1)
+ continue
+ else:
+ raise TargetdError(-303, "Unexpected exit code %d" % result)
+
+ raise TargetdError(-303, "Unable to execute command after "
+ "multiple retries %s" % (str(command)))
+
+
def _fs_hash():
fs_list = {}
for pool in pools:
full_path = os.path.join(pool, fs_path)
- # TODO take out this loop, used to handle bug in btrfs
- # ERROR: Failed to lookup path for root 0 - No such file or directory
- while True:
- result, out, err = invoke([fs_cmd, 'subvolume', 'list', '-ua',
- pool], False)
- if result == 0:
- data = split_stdout(out)
- if len(data):
- (total, free) = fs_space_values(full_path)
- for e in data:
- sub_vol = e[10]
-
- prefix = fs_path + '/'
-
- if sub_vol[:len(prefix)] == prefix:
- key = pool + '/' + sub_vol
- fs_list[key] = dict(name=sub_vol[len(prefix):],
- uuid=e[8],
- total_space=total,
- free_space=free,
- pool=pool,
- full_path=key)
- break
- elif result == 19:
- time.sleep(1)
- continue
- else:
- raise TargetdError(-303, "Unexpected exit code %d" % result)
+ result, out, err = _invoke_retries(
+ [fs_cmd, 'subvolume', 'list', '-ua', pool], False)
+
+ data = split_stdout(out)
+ if len(data):
+ (total, free) = fs_space_values(full_path)
+ for e in data:
+ sub_vol = e[10]
+
+ prefix = fs_path + os.path.sep
+
+ if sub_vol[:len(prefix)] == prefix:
+ key = os.path.join(pool, sub_vol)
+ fs_list[key] = dict(name=sub_vol[len(prefix):],
+ uuid=e[8],
+ total_space=total,
+ free_space=free,
+ pool=pool,
+ full_path=key)
return fs_list
@@ -253,28 +243,18 @@ def ss(req, fs_uuid, fs_cache=None):
full_path = os.path.join(fs_cache['pool'], ss_path, fs_cache['name'])
- # TODO take out this loop, used to handle bug in btrfs
- # ERROR: Failed to lookup path for root 0 - No such file or directory
-
if os.path.exists(full_path):
- while True:
- result, out, err = invoke([fs_cmd, 'subvolume', 'list', '-s',
- full_path], False)
- if result == 0:
- data = split_stdout(out)
- if len(data):
- for e in data:
- ts = "%s %s" % (e[10], e[11])
- time_epoch = int(time.mktime(
- time.strptime(ts, '%Y-%m-%d %H:%M:%S')))
- st = dict(name=e[-1], uuid=e[-3], timestamp=time_epoch)
- snapshots.append(st)
- break
- elif result == 19:
- time.sleep(1)
- continue
- else:
- raise TargetdError(-303, "Unexpected exit code %d" % result)
+ result, out, err = _invoke_retries([fs_cmd, 'subvolume', 'list', '-s',
+ full_path], False)
+
+ data = split_stdout(out)
+ if len(data):
+ for e in data:
+ ts = "%s %s" % (e[10], e[11])
+ time_epoch = int(time.mktime(
+ time.strptime(ts, '%Y-%m-%d %H:%M:%S')))
+ st = dict(name=e[-1], uuid=e[-3], timestamp=time_epoch)
+ snapshots.append(st)
return snapshots
diff --git a/targetd/main.py b/targetd/main.py
index fc7bc19..e86d7ac 100644
--- a/targetd/main.py
+++ b/targetd/main.py
@@ -21,14 +21,13 @@ import os
import setproctitle
import json
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-from threading import Lock
import yaml
import itertools
import socket
import ssl
import traceback
import logging as log
-import sys
+from utils import TargetdError
default_config_path = "/etc/target/targetd.yaml"
@@ -47,16 +46,10 @@ default_config = dict(
config = {}
-
-class TargetdError(Exception):
- def __init__(self, error_code, message, *args, **kwargs):
- Exception.__init__(self, *args, **kwargs)
- self.error = error_code
- self.msg = message
-
# Will be added to by fs/block.initialize()
mapping = dict()
+
class TargetHandler(BaseHTTPRequestHandler):
def log_request(self, code='-', size='-'):
diff --git a/targetd/nfs.py b/targetd/nfs.py
index 6b1d6c5..23fd396 100644
--- a/targetd/nfs.py
+++ b/targetd/nfs.py
@@ -11,12 +11,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from subprocess import Popen, PIPE
import re
import hashlib
import os
import os.path
import shlex
+from utils import invoke
def md5(t):
@@ -25,24 +25,6 @@ def md5(t):
return h.hexdigest()
-def invoke(cmd, raise_exception=True):
- """
- Exec a command returning a tuple (exit code, stdout, stderr) and optionally
- throwing an exception on non-zero exit code.
- """
- c = Popen(cmd, stdout=PIPE, stderr=PIPE)
- out = c.communicate()
-
- if raise_exception:
- if c.returncode != 0:
- cmd_str = str(cmd)
- raise RuntimeError('Unexpected exit code "%s" %s, out= %s' %
- (cmd_str, str(c.returncode),
- str(out[0] + out[1])))
-
- return c.returncode, out[0], out[1]
-
-
def make_line_array(out):
"""
Split the text out as an array of text strings
diff --git a/targetd/utils.py b/targetd/utils.py
index ff0396a..3d4b0fd 100644
--- a/targetd/utils.py
+++ b/targetd/utils.py
@@ -15,7 +15,7 @@
#
# Utility functions.
-
+from subprocess import Popen, PIPE
from contextlib import contextmanager
@contextmanager
@@ -24,3 +24,28 @@ def ignored(*exceptions):
yield
except exceptions:
pass
+
+
+class TargetdError(Exception):
+ def __init__(self, error_code, message, *args, **kwargs):
+ Exception.__init__(self, *args, **kwargs)
+ self.error = error_code
+ self.msg = message
+
+
+def invoke(cmd, raise_exception=True):
+ """
+ Exec a command returning a tuple (exit code, stdout, stderr) and optionally
+ throwing an exception on non-zero exit code.
+ """
+ c = Popen(cmd, stdout=PIPE, stderr=PIPE)
+ out = c.communicate()
+
+ if raise_exception:
+ if c.returncode != 0:
+ cmd_str = str(cmd)
+ raise TargetdError(-303, 'Unexpected exit code "%s" %s, out= %s' %
+ (cmd_str, str(c.returncode),
+ str(out[0] + out[1])))
+
+ return c.returncode, out[0], out[1]
--
1.8.2.1
10 years, 5 months
[PATCH 0/4] NFS/FS fixes
by Tony Asleson
This patch set addresses the following:
- Makes NFS changes persistent by writing them to /etc/exports.d/targetd.exports
- Fixes FS listings, btrfs behavior appears to have changed
Please review.
Known issues:
- `exportfs -v` doesn't double quote output of export paths with spaces.
Need to do a work around or patch exportfs.
Tony Asleson (4):
pep8: Clean-up
nfs.py: Make nfs export changes persistent V2
nfs.py: Only write out needed exports
fs.py: Fix FS listing
targetd/fs.py | 20 +++++--
targetd/nfs.py | 181 +++++++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 170 insertions(+), 31 deletions(-)
--
1.8.2.1
10 years, 5 months
[PATCH 1/2] pep8: Clean-up
by Tony Asleson
Fixed ws etc. and renamed _bitCount to _bc.
Signed-off-by: Tony Asleson <tasleson(a)redhat.com>
---
targetd/nfs.py | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/targetd/nfs.py b/targetd/nfs.py
index 083760e..6daf99e 100644
--- a/targetd/nfs.py
+++ b/targetd/nfs.py
@@ -76,7 +76,12 @@ class Export(object):
export_regex = '([\/a-zA-Z0-9\.-_]+)[\s]+(.+)\((.+)\)'
@staticmethod
- def _bitCount(int_type):
+ def _bc(int_type):
+ """
+ Bit count.
+
+ returns the number of bits set.
+ """
count = 0
while int_type:
int_type &= int_type - 1
@@ -86,23 +91,22 @@ class Export(object):
@staticmethod
def _validate_options(options):
- if Export._bitCount(((Export.RW | Export.RO) & options)) == 2:
+ if Export._bc(((Export.RW | Export.RO) & options)) == 2:
raise ValueError("Both RO & RW set")
- if Export._bitCount(((Export.INSECURE | Export.SECURE) & options)) == 2:
+ if Export._bc(((Export.INSECURE | Export.SECURE) & options)) == 2:
raise ValueError("Both INSECURE & SECURE set")
- if Export._bitCount(((Export.SYNC | Export.ASYNC) & options)) == 2:
+ if Export._bc(((Export.SYNC | Export.ASYNC) & options)) == 2:
raise ValueError("Both SYNC & ASYNC set")
- if Export._bitCount(((Export.HIDE | Export.NOHIDE) & options)) == 2:
+ if Export._bc(((Export.HIDE | Export.NOHIDE) & options)) == 2:
raise ValueError("Both HIDE & NOHIDE set")
- if Export._bitCount(((Export.WDELAY | Export.NO_WDELAY) & options)) \
- == 2:
+ if Export._bc(((Export.WDELAY | Export.NO_WDELAY) & options)) == 2:
raise ValueError("Both WDELAY & NO_WDELAY set")
- if Export._bitCount(((Export.ROOT_SQUASH | Export.NO_ROOT_SQUASH)
+ if Export._bc(((Export.ROOT_SQUASH | Export.NO_ROOT_SQUASH)
& options)) > 1:
raise ValueError("Only one option of ROOT_SQUASH, NO_ROOT_SQUASH, "
"can be specified")
@@ -205,7 +209,7 @@ class Nfs(object):
Return list of exports
"""
rc = []
- ec, out, error = invoke([Nfs.cmd, '-v'])
+ ec, out, error = invoke([Nfs.cmd, '-v'])
rc = Export.parse(out)
return rc
--
1.8.2.1
10 years, 5 months