Merge lp:~niedbalski/charms/precise/swift-storage/add-fstab-persist into lp:~openstack-charmers-archive/charms/trusty/swift-storage/next

Proposed by James Page
Status: Merged
Merged at revision: 29
Proposed branch: lp:~niedbalski/charms/precise/swift-storage/add-fstab-persist
Merge into: lp:~openstack-charmers-archive/charms/trusty/swift-storage/next
Diff against target: 198 lines (+136/-7)
3 files modified
hooks/charmhelpers/core/fstab.py (+114/-0)
hooks/charmhelpers/core/host.py (+20/-6)
hooks/swift_storage_utils.py (+2/-1)
To merge this branch: bzr merge lp:~niedbalski/charms/precise/swift-storage/add-fstab-persist
Reviewer Review Type Date Requested Status
OpenStack Charmers Pending
Review via email: mp+221689@code.launchpad.net

This proposal supersedes a proposal from 2014-05-23.

Description of the change

- Updated charm-helpers with fstab persist support
- Modified mount command for specify "xfs" filesystem type

To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

Hi Jorge

This all looks really good - I have it a test and the one comment I have is that its possible to add multiple entries for a single block device to /etc/fstab.

This happened in my testing as I use the ephemeral storage that cloud-init configures mounted on /mnt as storage for swift - linux deals with the double mounting OK - but it looks odd to a user.

Revision history for this message
James Page (james-page) wrote :

/dev/vda1 on / type ext4 (rw)
...
/dev/vdb on /mnt type xfs (rw)
/dev/vdb on /srv/node/vdb type xfs (rw)

Revision history for this message
James Page (james-page) wrote :

It might be worth checking and removing any existing mounted block device before adding an explicit mapping.

Revision history for this message
Jorge Niedbalski (niedbalski) wrote :

Hey james-page,

I tried to reproduce your comment adding the same block-device twice, with no success:

In [8]: Fstab.add('/dev/sdaf', '/mnt/sdaf', 'xfs', None)
Out[8]: <charmhelpers.core.fstab.Entry at 0x17abcd0>

In [9]: Fstab.add('/dev/sdaf', '/mnt/sdaf', 'xfs', None)
Out[9]: False

Does is that initial /dev/vdb on fstab.d/ directory?

30. By Jorge Niedbalski

Re-imported from ~charm-helpers, added support for UUID,LABEL entries

31. By Jorge Niedbalski

Re-imported charm-helpers from latest merged version

Revision history for this message
Jorge Niedbalski (niedbalski) wrote :

Updated with latest merged revision.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'hooks/charmhelpers/core/fstab.py'
2--- hooks/charmhelpers/core/fstab.py 1970-01-01 00:00:00 +0000
3+++ hooks/charmhelpers/core/fstab.py 2014-06-04 19:11:16 +0000
4@@ -0,0 +1,114 @@
5+#!/usr/bin/env python
6+# -*- coding: utf-8 -*-
7+
8+__author__ = 'Jorge Niedbalski R. <jorge.niedbalski@canonical.com>'
9+
10+import os
11+
12+
13+class Fstab(file):
14+ """This class extends file in order to implement a file reader/writer
15+ for file `/etc/fstab`
16+ """
17+
18+ class Entry(object):
19+ """Entry class represents a non-comment line on the `/etc/fstab` file
20+ """
21+ def __init__(self, device, mountpoint, filesystem,
22+ options, d=0, p=0):
23+ self.device = device
24+ self.mountpoint = mountpoint
25+ self.filesystem = filesystem
26+
27+ if not options:
28+ options = "defaults"
29+
30+ self.options = options
31+ self.d = d
32+ self.p = p
33+
34+ def __eq__(self, o):
35+ return str(self) == str(o)
36+
37+ def __str__(self):
38+ return "{} {} {} {} {} {}".format(self.device,
39+ self.mountpoint,
40+ self.filesystem,
41+ self.options,
42+ self.d,
43+ self.p)
44+
45+ DEFAULT_PATH = os.path.join(os.path.sep, 'etc', 'fstab')
46+
47+ def __init__(self, path=None):
48+ if path:
49+ self._path = path
50+ else:
51+ self._path = self.DEFAULT_PATH
52+ file.__init__(self, self._path, 'r+')
53+
54+ def _hydrate_entry(self, line):
55+ return Fstab.Entry(*filter(
56+ lambda x: x not in ('', None),
57+ line.strip("\n").split(" ")))
58+
59+ @property
60+ def entries(self):
61+ self.seek(0)
62+ for line in self.readlines():
63+ try:
64+ if not line.startswith("#"):
65+ yield self._hydrate_entry(line)
66+ except ValueError:
67+ pass
68+
69+ def get_entry_by_attr(self, attr, value):
70+ for entry in self.entries:
71+ e_attr = getattr(entry, attr)
72+ if e_attr == value:
73+ return entry
74+ return None
75+
76+ def add_entry(self, entry):
77+ if self.get_entry_by_attr('device', entry.device):
78+ return False
79+
80+ self.write(str(entry) + '\n')
81+ self.truncate()
82+ return entry
83+
84+ def remove_entry(self, entry):
85+ self.seek(0)
86+
87+ lines = self.readlines()
88+
89+ found = False
90+ for index, line in enumerate(lines):
91+ if not line.startswith("#"):
92+ if self._hydrate_entry(line) == entry:
93+ found = True
94+ break
95+
96+ if not found:
97+ return False
98+
99+ lines.remove(line)
100+
101+ self.seek(0)
102+ self.write(''.join(lines))
103+ self.truncate()
104+ return True
105+
106+ @classmethod
107+ def remove_by_mountpoint(cls, mountpoint, path=None):
108+ fstab = cls(path=path)
109+ entry = fstab.get_entry_by_attr('mountpoint', mountpoint)
110+ if entry:
111+ return fstab.remove_entry(entry)
112+ return False
113+
114+ @classmethod
115+ def add(cls, device, mountpoint, filesystem, options=None, path=None):
116+ return cls(path=path).add_entry(Fstab.Entry(device,
117+ mountpoint, filesystem,
118+ options=options))
119
120=== modified file 'hooks/charmhelpers/core/host.py'
121--- hooks/charmhelpers/core/host.py 2014-05-19 11:41:35 +0000
122+++ hooks/charmhelpers/core/host.py 2014-06-04 19:11:16 +0000
123@@ -17,6 +17,7 @@
124 from collections import OrderedDict
125
126 from hookenv import log
127+from fstab import Fstab
128
129
130 def service_start(service_name):
131@@ -35,7 +36,8 @@
132
133
134 def service_reload(service_name, restart_on_failure=False):
135- """Reload a system service, optionally falling back to restart if reload fails"""
136+ """Reload a system service, optionally falling back to restart if
137+ reload fails"""
138 service_result = service('reload', service_name)
139 if not service_result and restart_on_failure:
140 service_result = service('restart', service_name)
141@@ -144,7 +146,19 @@
142 target.write(content)
143
144
145-def mount(device, mountpoint, options=None, persist=False):
146+def fstab_remove(mp):
147+ """Remove the given mountpoint entry from /etc/fstab
148+ """
149+ return Fstab.remove_by_mountpoint(mp)
150+
151+
152+def fstab_add(dev, mp, fs, options=None):
153+ """Adds the given device entry to the /etc/fstab file
154+ """
155+ return Fstab.add(dev, mp, fs, options=options)
156+
157+
158+def mount(device, mountpoint, options=None, persist=False, filesystem="ext3"):
159 """Mount a filesystem at a particular mountpoint"""
160 cmd_args = ['mount']
161 if options is not None:
162@@ -155,9 +169,9 @@
163 except subprocess.CalledProcessError, e:
164 log('Error mounting {} at {}\n{}'.format(device, mountpoint, e.output))
165 return False
166+
167 if persist:
168- # TODO: update fstab
169- pass
170+ return fstab_add(device, mountpoint, filesystem, options=options)
171 return True
172
173
174@@ -169,9 +183,9 @@
175 except subprocess.CalledProcessError, e:
176 log('Error unmounting {}\n{}'.format(mountpoint, e.output))
177 return False
178+
179 if persist:
180- # TODO: update fstab
181- pass
182+ return fstab_remove(mountpoint)
183 return True
184
185
186
187=== modified file 'hooks/swift_storage_utils.py'
188--- hooks/swift_storage_utils.py 2014-04-07 14:50:34 +0000
189+++ hooks/swift_storage_utils.py 2014-06-04 19:11:16 +0000
190@@ -181,7 +181,8 @@
191 _dev = os.path.basename(dev)
192 _mp = os.path.join('/srv', 'node', _dev)
193 mkdir(_mp, owner='swift', group='swift')
194- mount(dev, '/srv/node/%s' % _dev, persist=True)
195+ mount(dev, '/srv/node/%s' % _dev, persist=True,
196+ filesystem="xfs")
197 check_call(['chown', '-R', 'swift:swift', '/srv/node/'])
198 check_call(['chmod', '-R', '0750', '/srv/node/'])
199

Subscribers

People subscribed via source and target branches