Merge lp:~adalbas/ibmcharms/gpfs-config into lp:ibmcharms

Proposed by Adalberto Medeiros
Status: Merged
Merged at revision: 27
Proposed branch: lp:~adalbas/ibmcharms/gpfs-config
Merge into: lp:ibmcharms
Diff against target: 482 lines (+167/-64)
10 files modified
charms/trusty/gpfs/README.md (+5/-1)
charms/trusty/gpfs/config.yaml (+6/-0)
charms/trusty/gpfs/hooks/common-relation-changed (+5/-3)
charms/trusty/gpfs/hooks/common-relation-joined (+6/-3)
charms/trusty/gpfs/hooks/config-changed (+35/-2)
charms/trusty/gpfs/hooks/gpfshooklib.py (+90/-12)
charms/trusty/gpfs/hooks/install (+18/-42)
charms/trusty/gpfs/hooks/start (+1/-0)
charms/trusty/gpfs/hooks/stop (+1/-0)
charms/trusty/gpfs/tests/10-deploy (+0/-1)
To merge this branch: bzr merge lp:~adalbas/ibmcharms/gpfs-config
Reviewer Review Type Date Requested Status
Michael Chase-Salerno Approve
Review via email: mp+251319@code.launchpad.net

Description of the change

Add install to gpfshooklib.py
Add config-changed. Installation is done here if gpfs_url was not set before.
Add unit test. Still not fully tested

To post a comment you must log in.
Revision history for this message
Michael Chase-Salerno (mcs-chasal) wrote :

Looks good to me.

review: Approve
lp:~adalbas/ibmcharms/gpfs-config updated
27. By Adalberto Medeiros

Changes on installation for config-changed

28. By Adalberto Medeiros

Merge with dnsfixes

29. By Adalberto Medeiros

Fix pep8

30. By Adalberto Medeiros

merge tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charms/trusty/gpfs/README.md'
2--- charms/trusty/gpfs/README.md 2015-01-27 12:40:23 +0000
3+++ charms/trusty/gpfs/README.md 2015-03-09 15:35:58 +0000
4@@ -30,13 +30,17 @@
5 Configure config.yaml with the repository url
6
7 gpfs_url: "http://<server-name>/debs/gpfs4.1"
8- **Packages.gz should be on the same directory as the packages. The install hook will add Linux/x86_64 to the URL
9+ **Packages.gz should be on the same directory as the packages. The install hook will add Linux/x86_64 to the URL**
10
11+You can also set gpfs_url with "juju set" after deploy the charm
12 ## Deploy
13
14 juju deploy gpfs gpfs-manager
15 juju deploy gpfs gpfs-client
16
17+ # If gpfs_url is not set
18+ juju set gpfs-manager gpfs_url="http://<server-name>/debs/gpfs4.1"
19+
20 juju add relation gpfs-manager:manager gpfs-client:client
21
22 # Configuration
23
24=== modified file 'charms/trusty/gpfs/config.yaml'
25--- charms/trusty/gpfs/config.yaml 2015-01-27 12:19:54 +0000
26+++ charms/trusty/gpfs/config.yaml 2015-03-09 15:35:58 +0000
27@@ -11,3 +11,9 @@
28 type: string
29 default: "4.1"
30 description: "Version of GPFS"
31+ quorum:
32+ type: string
33+ default: "quorum"
34+ description: >
35+ Designation for nodes. Values can be quorum,
36+ non-quorum or empty string (this assumes non-quorum)
37
38=== modified file 'charms/trusty/gpfs/hooks/common-relation-changed'
39--- charms/trusty/gpfs/hooks/common-relation-changed 2015-03-03 17:57:57 +0000
40+++ charms/trusty/gpfs/hooks/common-relation-changed 2015-03-09 15:35:58 +0000
41@@ -24,13 +24,15 @@
42 rlhn = hookenv.relation_get(attribute='lhostname', unit=runit, rid=relid)
43 llhn = socket.getfqdn()
44 if not rlhn is None:
45- gpfshooklib.chk_dns(rlhn,rip)
46+ gpfshooklib.chk_dns(rlhn, rip)
47
48 if hookname == "client-relation-changed":
49 # Save the keypair from the manager
50 log("Copying keys to client")
51- pubkey = hookenv.relation_get(attribute='pubkey', unit=runit, rid=relid)
52- privkey = hookenv.relation_get(attribute='privkey', unit=runit, rid=relid)
53+ pubkey = hookenv.relation_get(attribute='pubkey', unit=runit,
54+ rid=relid)
55+ privkey = hookenv.relation_get(attribute='privkey', unit=runit,
56+ rid=relid)
57 gpfshooklib.set_ssh_key(pubkey, private=False)
58 gpfshooklib.set_ssh_key(privkey, private=True)
59 if hookname == "manager-relation-changed" and not rlhn is None:
60
61=== modified file 'charms/trusty/gpfs/hooks/common-relation-joined'
62--- charms/trusty/gpfs/hooks/common-relation-joined 2015-03-03 17:57:57 +0000
63+++ charms/trusty/gpfs/hooks/common-relation-joined 2015-03-09 15:35:58 +0000
64@@ -12,6 +12,7 @@
65 )
66
67 log = hookenv.log
68+config = hookenv.config()
69
70
71 def main():
72@@ -34,11 +35,13 @@
73 })
74 if hookname == "client-relation-joined":
75 # Set the node designation values and hostname
76+ quorum = gpfshooklib.validate_quorum(config.get('quorum'))
77 hookenv.relation_set(hookenv.relation_id(), {
78- 'quorum': 'quorum',
79+ 'hostname': socket.gethostname(),
80+ 'quorum': quorum,
81 'client': 'client'
82- })
83-
84+ })
85+
86 # Configure sshd to allow root ssh
87 # Avoid the host key confirmation (all relation-joined)
88 gpfshooklib.configure_ssh()
89
90=== modified file 'charms/trusty/gpfs/hooks/config-changed'
91--- charms/trusty/gpfs/hooks/config-changed 2015-01-21 19:48:09 +0000
92+++ charms/trusty/gpfs/hooks/config-changed 2015-03-09 15:35:58 +0000
93@@ -9,8 +9,7 @@
94 hookenv,
95 host,
96 )
97-
98-#from start import start
99+import gpfshooklib
100
101 hooks = hookenv.Hooks()
102 log = hookenv.log
103@@ -22,15 +21,49 @@
104 def config_changed():
105 config = hookenv.config()
106
107+ install_bool = False
108 for key in config:
109 if config.changed(key):
110 log("config['{}'] changed from {} to {}".format(
111 key, config.previous(key), config[key]))
112+ if key in ['gpfs_url', 'version', 'update']:
113+ install_bool = True
114+
115+ # If installation configuration has changed, reinstall gpfs
116+ log("Installation: %s" % install_bool)
117+ gpfs_url = config['gpfs_url']
118+ version = config['version']
119+ update = config['update']
120+
121+ # exit if there is no source
122+ gpfshooklib.check_empty_source(gpfs_url)
123+ # If source changed, install packages from new source
124+ if install_bool:
125+ install_gpfs(gpfs_url, version, update)
126+
127+ # if quorum changed, change node designation
128+ if config.changed('quorum'):
129+ unit = hookenv.local_unit()
130+ quorum = config.get('quorum')
131+ change_node_designation(unit, quorum)
132
133 config.save()
134 #start.start()
135
136
137+def install_gpfs(gpfs_url, version, update):
138+ # install gpfs
139+
140+ gpfshooklib.gpfs_install(gpfs_url, version)
141+ gpfshooklib.gpfs_install_updates(gpfs_url, version, update)
142+ gpfshooklib.build_modules()
143+
144+
145+def change_node_designation(unit, quorum='quorum'):
146+ # TODO, change unit designation to quorum or non-quorum
147+ pass
148+
149+
150 if __name__ == "__main__":
151 # execute a hook based on the name the program is called by
152 hooks.execute(sys.argv)
153
154=== modified file 'charms/trusty/gpfs/hooks/gpfshooklib.py'
155--- charms/trusty/gpfs/hooks/gpfshooklib.py 2015-03-03 17:57:57 +0000
156+++ charms/trusty/gpfs/hooks/gpfshooklib.py 2015-03-09 15:35:58 +0000
157@@ -7,24 +7,75 @@
158 import tempfile
159 import socket
160 from shlex import split
161+import subprocess
162 from subprocess import (
163 call,
164 check_call,
165- check_output
166+ check_output,
167+ Popen,
168+ CalledProcessError
169 )
170
171 sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib'))
172
173+from charmhelpers import fetch
174 from charmhelpers.core import (
175 hookenv,
176 )
177 log = hookenv.log
178
179+GPFS_PATH = '/Linux/x86_64'
180+
181+
182 def add_to_path(p, new):
183 return p if new in p.split(':') else p + ':' + new
184
185 os.environ['PATH'] = add_to_path(os.environ['PATH'], '/usr/lpp/mmfs/bin')
186
187+
188+## installation methods ##
189+def _get_source(url, source_dir=""):
190+ return "deb %s%s ./" % (url, source_dir)
191+
192+
193+def check_empty_source(gpfs_url):
194+ # Check if there is a repository to install from
195+ # TODO: check if packages are already installed
196+ if not gpfs_url:
197+ log("No GPFS source available. Use juju set gpfs gpfs_url=<url> "
198+ "to install packages. See README for more info.", log.ERROR)
199+ sys.exit(0)
200+
201+
202+def gpfs_install(url, version):
203+ # install main gpfs packages
204+ gpfs_source = _get_source(url, source_dir=GPFS_PATH)
205+ log('Gpfs source' + gpfs_source)
206+
207+ # Add gpfs source and update apt
208+ fetch.add_source(gpfs_source)
209+ try:
210+ fetch.apt_update(fatal=True)
211+ # Install gpfs packages
212+ fetch.apt_install("gpfs*", options=["--allow-unauthenticated"],
213+ fatal=True)
214+ except CalledProcessError:
215+ #TODO: verify source was configured correctly
216+ raise
217+
218+
219+def gpfs_install_updates(url, version, update=True):
220+ # install update packages (patches), if given
221+ if update:
222+ log('Applying patches')
223+ source_dir = '/gpfs' + version + '_patches' + GPFS_PATH
224+ patch_source = _get_source(url, source_dir=source_dir)
225+ fetch.add_source(patch_source)
226+ fetch.apt_update(fatal=True)
227+ fetch.apt_install("gpfs*", options=["--allow-unauthenticated"],
228+ fatal=True)
229+
230+
231 ## ssh key methods ##
232 def create_ssh_keys():
233 # Generate ssh keys if needed
234@@ -34,7 +85,8 @@
235 # Ensure permissions are good
236 os.chmod('/root/.ssh/id_rsa.pub', 0600)
237 os.chmod('/root/.ssh/id_rsa', 0600)
238-
239+
240+
241 def get_ssh_keys():
242 # get public and private ssh keys
243 with open("/root/.ssh/id_rsa.pub", "r") as idfile:
244@@ -48,9 +100,10 @@
245 idfile.close()
246 return [privkey, pubkey]
247
248+
249 def set_ssh_key(key, private=False):
250 if key:
251- if private == False:
252+ if private is False:
253 f = open("/root/.ssh/id_rsa.pub", "w")
254 f.write(key)
255 f.close()
256@@ -65,6 +118,7 @@
257 f.close()
258 os.chmod('/root/.ssh/id_rsa', 0600)
259
260+
261 def configure_ssh():
262 # Configure sshd_config file to allow root
263 sshconf = open("/etc/ssh/sshd_config", 'r')
264@@ -91,53 +145,78 @@
265 idfile.write("StrictHostKeyChecking no\n")
266 idfile.close()
267
268+
269+## Other utility methods##
270+def validate_quorum(quorum):
271+ valid_values = ['', 'quorum', 'non-quorum']
272+ return quorum if quorum in valid_values else ''
273+
274+
275 ## cluster management methods ##
276+def build_modules():
277+# build binary gpfs modules after installation
278+ try:
279+ check_call(["mmbuildgpl"])
280+ except CalledProcessError:
281+ log('mmbuildgpl was not executed', level=hookenv.WARNING)
282+ except OSError:
283+ log('mmbuildgpl not found/installed')
284+
285
286 def start():
287 # Only manager can start/stop cluster
288 if is_manager():
289 log(check_output(split('mmstartup -a')))
290
291+
292 def stop():
293 # stop the server
294 if is_manager():
295 check_output(split('mmshutdown -a'))
296
297+
298 def node_exists(nodename):
299 # Check if node has already been added to cluster
300 lscluster = check_output('mmlscluster')
301 node = re.search('^.*\d+.*%s.*\n' % nodename, lscluster, re.M)
302 return False if node is None else True
303
304+
305 def add_node(nodename, m_designation='client', q_designation='nonquorum'):
306 # add new node to the cluster
307 if cluster_exists() and not node_exists(nodename):
308- log(check_output(split('mmaddnode -N %s:%s-%s' % \
309- (nodename, m_designation, q_designation))))
310+ log(check_output(split('mmaddnode -N %s:%s-%s' %
311+ (nodename, m_designation, q_designation))))
312 else:
313 log('Node %s could not be added. Manager not defined' % nodename)
314-
315+
316+
317 def apply_license(nodename):
318 check_output(split('mmchlicense server --accept -N %s' % nodename))
319
320+
321 def set_manager_file():
322 # define a file that indicates the node is a manager
323- open("/var/mmfs/.manager","a").close()
324+ open("/var/mmfs/.manager", "a").close()
325+
326
327 def is_manager():
328 # check if the node is a manager
329 if os.path.exists("/var/mmfs/.manager"):
330 return True
331
332+
333 def cluster_exists():
334 # Check if cluster is already defined
335 return True if call('mmlscluster') == 0 else False
336-
337+
338+
339 def create_cluster(hostname):
340 # create the cluster for the hostname, manager only
341 if is_manager() and not cluster_exists():
342- log(check_output(split('mmcrcluster -N %s:quorum-manager' % \
343- hostname + ' -r /usr/bin/ssh -R /usr/bin/scp')))
344+ log(check_output(split('mmcrcluster -N %s:quorum-manager' %
345+ hostname + ' -r /usr/bin/ssh -R /usr/bin/scp')))
346+
347
348 def chk_dns(hostname, ip):
349 try:
350@@ -145,6 +224,5 @@
351 except:
352 log("Hostname not resolving, adding to /etc/hosts")
353 with open("/etc/hosts", "a") as hostfile:
354- hostfile.write("%s %s\n" % (ip, hostname) )
355+ hostfile.write("%s %s\n" % (ip, hostname))
356 hostfile.close()
357-
358
359=== modified file 'charms/trusty/gpfs/hooks/install'
360--- charms/trusty/gpfs/hooks/install 2015-02-09 11:42:31 +0000
361+++ charms/trusty/gpfs/hooks/install 2015-03-09 15:35:58 +0000
362@@ -11,66 +11,42 @@
363 hookenv,
364 )
365
366+import gpfshooklib
367+
368 hooks = hookenv.Hooks()
369 log = hookenv.log
370 config = hookenv.config()
371
372-SERVICE = 'gpfs'
373-
374+# development packages needed to build kernel modules for GPFS cluster
375 PREREQS = ["ksh", "binutils", "m4", "libaio1", "g++", "cpp", "make", "gcc"]
376-# TODO: gpfs.msg.en_us - change it to any language
377-GPFS_PKGS = ["gpfs.base", "gpfs.crypto", "gpfs.docs", "gpfs.ext",
378- "gpfs.gpl", "gpfs.gski", "gpfs.msg.en_us"]
379-GPFS_PATH = '/Linux/x86_64'
380+
381
382 @hooks.hook('install')
383 def install():
384 log('Installing gpfs')
385
386 # Things that need to happen here
387- # Fetch GPFS packages from user given location?
388 gpfs_url = config.get('gpfs_url')
389 version = config.get('version')
390 update = config.get('update') # boolean value whether to apply patches
391
392- gpfs_source = get_source(gpfs_url, source_dir=GPFS_PATH)
393- log('Gpfs source' + gpfs_source)
394-
395- # Add gpfs source and update apt
396- fetch.add_source(gpfs_source)
397- fetch.apt_update()
398- # Apt install prereqs
399- fetch.apt_install(PREREQS)
400- # install kernel prereq
401+ # install kernel prereq and other prereqs
402 linux_headers = "linux-headers-%s" % get_kernel_version()
403- fetch.apt_install(linux_headers)
404-
405- # Install gpfs packages
406- fetch.apt_install("gpfs*", options=["--allow-unauthenticated"])
407-
408- # Apply patch packages
409- if update:
410- log('Applying patches')
411- source_dir = '/gpfs' + version + '_patches' + GPFS_PATH
412- patch_source = get_source(gpfs_url, source_dir=source_dir)
413- fetch.add_source(patch_source)
414- fetch.apt_update()
415- fetch.apt_install("gpfs*", options=["--allow-unauthenticated"])
416-
417- # Build binary modules
418- os.environ['PATH'] += (':/usr/lpp/mmfs/bin')
419- try:
420- subprocess.check_call(["mmbuildgpl"])
421- except subprocess.CalledProcessError:
422- log('mmbuildgpl was not executed', level=hookenv.WARNING)
423- except OSError:
424- log('mmbuildgpl not found/installed')
425-
426-def get_source(url, source_dir=""):
427- return "deb %s%s ./" % (url,source_dir)
428+ fetch.apt_install(PREREQS + [linux_headers])
429+
430+ if gpfs_url == "":
431+ log("""No GPFS source packages. Use juju set gpfs gpfs_url=<url>
432+ to install packages. See README for more info""",
433+ level=hookenv.ERROR)
434+ sys.exit(0)
435+
436+ gpfshooklib.gpfs_install(gpfs_url, version)
437+ gpfshooklib.gpfs_install_updates(gpfs_url, version, update)
438+ gpfshooklib.build_modules()
439+
440
441 def get_kernel_version():
442- return subprocess.check_output(['uname','-r']).strip()
443+ return subprocess.check_output(['uname', '-r']).strip()
444
445 if __name__ == "__main__":
446 # execute a hook based on the name the program is called by
447
448=== modified file 'charms/trusty/gpfs/hooks/start'
449--- charms/trusty/gpfs/hooks/start 2015-02-10 02:11:55 +0000
450+++ charms/trusty/gpfs/hooks/start 2015-03-09 15:35:58 +0000
451@@ -15,6 +15,7 @@
452 hooks = hookenv.Hooks()
453 log = hookenv.log
454
455+
456 @hooks.hook('start')
457 def start():
458 log("Starting cluster (manager only)")
459
460=== modified file 'charms/trusty/gpfs/hooks/stop'
461--- charms/trusty/gpfs/hooks/stop 2015-02-10 02:11:55 +0000
462+++ charms/trusty/gpfs/hooks/stop 2015-03-09 15:35:58 +0000
463@@ -14,6 +14,7 @@
464 hooks = hookenv.Hooks()
465 log = hookenv.log
466
467+
468 @hooks.hook('stop')
469 def stop():
470 gpfshooklib.stop()
471
472=== modified file 'charms/trusty/gpfs/tests/10-deploy'
473--- charms/trusty/gpfs/tests/10-deploy 2015-03-09 15:24:07 +0000
474+++ charms/trusty/gpfs/tests/10-deploy 2015-03-09 15:35:58 +0000
475@@ -25,7 +25,6 @@
476
477 unit_manager_0 = d.sentry.unit['gpfs/0']
478 unit_client_0 = d.sentry.unit['gpfs-client/0']
479-
480 print(unit_manager_0.info)
481
482 # verify unit_manager is manager

Subscribers

People subscribed via source and target branches