Merge lp:~mattyw/charms/trusty/mongodb/mongodb-backup into lp:charms/trusty/mongodb

Proposed by Matthew Williams
Status: Merged
Merged at revision: 78
Proposed branch: lp:~mattyw/charms/trusty/mongodb/mongodb-backup
Merge into: lp:charms/trusty/mongodb
Diff against target: 502 lines (+323/-28)
12 files modified
Makefile (+3/-1)
actions.yaml (+22/-0)
actions/backup.py (+56/-0)
actions/backup_test.py (+52/-0)
actions/dump (+4/-0)
actions/restore (+4/-0)
charm-helpers-sync.yaml (+1/-1)
charmhelpers/core/hookenv.py (+43/-9)
charmhelpers/core/host.py (+32/-16)
charmhelpers/core/hugepage.py (+8/-1)
charmhelpers/core/kernel.py (+68/-0)
charmhelpers/core/strutils.py (+30/-0)
To merge this branch: bzr merge lp:~mattyw/charms/trusty/mongodb/mongodb-backup
Reviewer Review Type Date Requested Status
Charles Butler (community) Approve
Domas Monkus (community) Approve
Marco Ceppi (community) Needs Fixing
Ryan Beisner (community) Needs Fixing
Review via email: mp+273544@code.launchpad.net

Commit message

Added actions/dump and actions/restore

These are actions that run mongodump and mongorestore.

Both actions take two parameters, the list of arguments and the workingDirectory. The simplest use case is just

juju action do mongodb/0 dump
# SSH into mongodb - drop all the data
juju action do mongodb/0 restore
# SSH into mongo to confirm the data is restored

Description of the change

Added actions/dump and actions/restore

These are actions that run mongodump and mongorestore.

Both actions take two parameters, the list of arguments and the workingDirectory. The simplest use case is just

juju action do mongodb/0 dump
# SSH into mongodb - drop all the data
juju action do mongodb/0 restore
# SSH into mongo to confirm the data is restored

To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #11389 mongodb for mattyw mp273544
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/11389/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #10582 mongodb for mattyw mp273544
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/10582/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #7136 mongodb for mattyw mp273544
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/12697628/
Build: http://10.245.162.77:8080/job/charm_amulet_test/7136/

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Looks like a random interwebs failure during the apt process in the install hook on one of the mongo units. Re-triggering amulet test...

Revision history for this message
Ryan Beisner (1chb1n) wrote :

FYI, for the curious, this was where it stumbled (seemingly unrelated to the proposed changes):

2015-10-06 15:51:38 INFO install W: Failed to fetch http://nova.clouds.archive.ubuntu.com/ubuntu/dists/trusty-updates/main/i18n/Translation-en Hash Sum mismatch

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Please adjust the Makefile in your proposal to add lint test coverage of the new actions dir:

- .venv/bin/flake8 --exclude hooks/charmhelpers hooks tests unit_tests

+ .venv/bin/flake8 --exclude hooks/charmhelpers actions hooks tests unit_tests

Also: By default, flake8 will not check files in a directory unless they have a .py extension. Please use the .py extension on the action files.

Thank you

review: Needs Fixing
Revision history for this message
Ryan Beisner (1chb1n) wrote :

@mattw

RE: irc discussion, yes, if you can adjust the existing action along with your new actions, that would be great.

I would bzr mv the action files to add the .py extensions, then add a symlink of the old action filename to the new .py filename.

Here is an example of this approach in different charm:

openstack_upgrade --> symlinks to --> openstack_upgrade.py

http://bazaar.launchpad.net/~openstack-charmers/charms/trusty/swift-storage/next/files/head:/actions/

Thanks again!

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #7139 mongodb for mattyw mp273544
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/7139/

Revision history for this message
Marco Ceppi (marcoceppi) wrote :

I've got a few suggestions.

First, we have action-get, action-set, and action-fail in charmhelpers. I'd consider re-syncing charm-helpers in hooks/charmhelpers to include these updated methods then importing them in the actions files.

Also, symlinking to a .py file is a bit tedious, instead to address the lack of linting coverage, I'd recommend the following patch: http://paste.ubuntu.com/12698613/ which addresses the lack of lint coverage without creating symlinks.

review: Needs Fixing
Revision history for this message
Ryan Beisner (1chb1n) wrote :

@mattw

From the test perspective: as long as the action code gets test coverage, I'm agnostic to how that is achieved in this charm.

Marco's example of adding file inspection logic to the Makefile is quite clever and a totally acceptable approach. Thanks @marcoceppi!

80. By Matthew Williams

Makefile: Added lint support for the actions, fixed linting issues found

81. By Matthew Williams

charmhelpers: Resync

82. By Matthew Williams

charmhelpers: sync

83. By Matthew Williams

actions/backup: Refactored the backup actions to allow unit testing

84. By Matthew Williams

actions/backup: unit tests for actions

85. By Matthew Williams

action/backup: Use the action functions from charmhelpers

Revision history for this message
Matthew Williams (mattyw) wrote :

@beisner @marcoceppi PTAL

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #11483 mongodb for mattyw mp273544
    LINT FAIL: lint-test failed

LINT Results (max last 2 lines):
make: *** [lint] Error 1
ERROR:root:Make target returned non-zero.

Full lint test output: http://paste.ubuntu.com/12705417/
Build: http://10.245.162.77:8080/job/charm_lint_check/11483/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #10676 mongodb for mattyw mp273544
    UNIT FAIL: unit-test failed

UNIT Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.

Full unit test output: http://paste.ubuntu.com/12705419/
Build: http://10.245.162.77:8080/job/charm_unit_test/10676/

86. By Matthew Williams

actions/backup: Don't need this import anymore

Revision history for this message
Domas Monkus (tasdomas) :
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #11485 mongodb for mattyw mp273544
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/11485/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #10677 mongodb for mattyw mp273544
    UNIT FAIL: unit-test failed

UNIT Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.

Full unit test output: http://paste.ubuntu.com/12705619/
Build: http://10.245.162.77:8080/job/charm_unit_test/10677/

Revision history for this message
Matthew Williams (mattyw) wrote :

Sorry for the large diff. charmhelpers has been moved to location accessible by hooks and actions.

PTAL

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #11487 mongodb for mattyw mp273544
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/11487/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #10679 mongodb for mattyw mp273544
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/10679/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #7186 mongodb for mattyw mp273544
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/7186/

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Tip:

If you'd like to drastically reduce the diff, while achieving the same effect:

Revert back to 86: bzr uncommit && bzr revert

Then bzr mv hooks/charmhelpers instead of mv, and do your linking after that. This will keep the version control side of things happier.

Then commit and bzr push with --overwrite.

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #7188 mongodb for mattyw mp273544
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/7188/

87. By Matthew Williams

charmhelpers: Moved to common location

88. By Matthew Williams

charmhelpers: symlinks

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #11489 mongodb for mattyw mp273544
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/11489/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #10680 mongodb for mattyw mp273544
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/10680/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #7190 mongodb for mattyw mp273544
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/12706279/
Build: http://10.245.162.77:8080/job/charm_amulet_test/7190/

Revision history for this message
Ryan Beisner (1chb1n) wrote :

^ that amulet test failure was unrelated to the proposed changes, rerunning...

2015-10-07 17:05:59 INFO install W: Failed to fetch http://nova.clouds.archive.ubuntu.com/ubuntu/dists/trusty-updates/main/i18n/Translation-en Hash Sum mismatch

https://bugs.launchpad.net/ubuntu/+source/apt/+bug/972077

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #7206 mongodb for mattyw mp273544
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/12711117/
Build: http://10.245.162.77:8080/job/charm_amulet_test/7206/

Revision history for this message
Domas Monkus (tasdomas) wrote :

A few comments inline with the code.

review: Needs Fixing
89. By Matthew Williams

actions/backups.py: Fixed comments from domas' review

Revision history for this message
Matthew Williams (mattyw) wrote :

> charm_amulet_test #7206 mongodb for mattyw mp273544
> AMULET FAIL: amulet-test failed
>
> AMULET Results (max last 2 lines):
> make: *** [functional_test] Error 1
> ERROR:root:Make target returned non-zero.
>
> Full amulet test output: http://paste.ubuntu.com/12711117/
> Build: http://10.245.162.77:8080/job/charm_amulet_test/7206/

The output of this amulet tests seems to show that when three mongodb units were started in a replica set we ended up in a situation where there were two primaries. This is a known problem with the existing charm right? Seems like the tests should be altered?

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #11504 mongodb for mattyw mp273544
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/11504/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #10696 mongodb for mattyw mp273544
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/10696/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #7208 mongodb for mattyw mp273544
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/7208/

Revision history for this message
Domas Monkus (tasdomas) wrote :

looks good to me

review: Approve
Revision history for this message
Charles Butler (lazypower) wrote :

+1 LGTM

Approved and merged. Thanks for the contribution Mattyw

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2014-12-11 06:29:02 +0000
+++ Makefile 2015-10-08 08:12:47 +0000
@@ -14,6 +14,7 @@
14# along with this program. If not, see <http://www.gnu.org/licenses/>.14# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
16PYTHON := /usr/bin/env python16PYTHON := /usr/bin/env python
17ACTIONS := $(shell grep -slE '\#!(.*)python' actions/*)
1718
18clean:19clean:
19 rm -f .coverage20 rm -f .coverage
@@ -27,11 +28,12 @@
27 .venv/bin/pip install -I -r test_requirements.txt28 .venv/bin/pip install -I -r test_requirements.txt
2829
29lint: .venv30lint: .venv
30 .venv/bin/flake8 --exclude hooks/charmhelpers hooks tests unit_tests31 .venv/bin/flake8 --exclude hooks/charmhelpers actions $(ACTIONS) hooks tests unit_tests
3132
32test: .venv33test: .venv
33 @echo Starting unit tests...34 @echo Starting unit tests...
34 .venv/bin/nosetests -s --nologcapture --with-coverage $(EXTRA) unit_tests/35 .venv/bin/nosetests -s --nologcapture --with-coverage $(EXTRA) unit_tests/
36 .venv/bin/nosetests -s --nologcapture --with-coverage $(EXTRA) actions/
3537
36functional_test:38functional_test:
37 @echo Starting amulet tests...39 @echo Starting amulet tests...
3840
=== modified file 'actions.yaml'
--- actions.yaml 2015-05-07 20:42:32 +0000
+++ actions.yaml 2015-10-08 08:12:47 +0000
@@ -47,3 +47,25 @@
47 Only use syncDelay in conjunction with mmf set to true.47 Only use syncDelay in conjunction with mmf set to true.
48 type: integer48 type: integer
49 default: 049 default: 0
50dump:
51 description: Runs the mongodump command
52 params:
53 args:
54 description: The arguments to pass to the mongodump command
55 type: string
56 default: ""
57 workingDir:
58 description: The directory to run the mongodump command from.
59 type: string
60 default: "/tmp/mongodump"
61restore:
62 description: Runs the mongorestore command
63 params:
64 args:
65 description: The arguments to pass to the mongorestore command
66 type: string
67 default: ""
68 workingDir:
69 description: The directory to run the mongorestore command from.
70 type: string
71 default: "/tmp/mongodump"
5072
=== added file 'actions/backup.py'
--- actions/backup.py 1970-01-01 00:00:00 +0000
+++ actions/backup.py 2015-10-08 08:12:47 +0000
@@ -0,0 +1,56 @@
1import subprocess
2import os
3try:
4 from charmhelpers.core.hookenv import action_get, action_set, action_fail
5except ImportError:
6 subprocess.check_call(['apt-get', 'install', '-y', 'python-pip'])
7 subprocess.check_call(['pip', 'install', 'charmhelpers'])
8 from charmhelpers.core.hookenv import action_get, action_set, action_fail
9
10
11def mkdir(dir):
12 return os.makedirs(dir)
13
14
15def execute(command, current_working_directory):
16 return subprocess.check_output(
17 " ".join(command),
18 cwd=current_working_directory,
19 )
20
21
22def dump():
23 args = str(action_get("args")).strip()
24 dir = str(action_get("workingDir"))
25 backup_command("mongodump", args, dir)
26
27
28def restore():
29 args = str(action_get("args")).strip()
30 dir = str(action_get("workingDir"))
31 backup_command("mongorestore", args, dir)
32
33
34def backup_command(cmd, args, dir):
35 try:
36 mkdir(dir)
37 except OSError, e:
38 pass # Ignoring, the directory already exists
39 except Exception, e:
40 action_set({"directory creation exception": e})
41 action_fail(e)
42 return
43
44 command = cmd + " " + args
45 command = command.strip()
46 action_set({"command": command, "working-dir": dir})
47 try:
48 output = execute(command, dir)
49 action_set({"output": output})
50 except subprocess.CalledProcessError, e:
51 action_set({"error_code": e.returncode,
52 "exception": e, "output": e.output})
53 action_fail(e)
54 except Exception, e:
55 action_set({"exception": e})
56 action_fail(e)
057
=== added file 'actions/backup_test.py'
--- actions/backup_test.py 1970-01-01 00:00:00 +0000
+++ actions/backup_test.py 2015-10-08 08:12:47 +0000
@@ -0,0 +1,52 @@
1import unittest
2from mock import create_autospec, call
3import backup
4
5
6def mock_action_get(key):
7 return {"workingDir": "this/dir", "args": "-arg1 -arg2"}[key]
8
9
10class TestBackups(unittest.TestCase):
11
12 def test_dump(self):
13 mkdir = create_autospec(backup.mkdir, return_value=True)
14 execute = create_autospec(backup.execute, return_value="output")
15 action_set = create_autospec(backup.action_set, return_value=None)
16 action_fail = create_autospec(backup.action_fail, return_value=None)
17 backup.mkdir = mkdir
18 backup.execute = execute
19 backup.action_set = action_set
20 backup.action_fail = action_fail
21 backup.action_get = mock_action_get
22
23 backup.dump()
24
25 mkdir.assert_called_once_with("this/dir")
26 execute.assert_called_once_with("mongodump -arg1 -arg2", "this/dir")
27 action_set.assert_has_calls([
28 call({"command": "mongodump -arg1 -arg2",
29 "working-dir": "this/dir"}),
30 call({"output": "output"})])
31
32 def test_restore(self):
33 mkdir = create_autospec(backup.mkdir, return_value=True)
34 execute = create_autospec(backup.execute, return_value="output")
35 action_set = create_autospec(backup.action_set, return_value=None)
36 action_fail = create_autospec(backup.action_fail, return_value=None)
37 backup.mkdir = mkdir
38 backup.execute = execute
39 backup.action_set = action_set
40 backup.action_fail = action_fail
41
42 backup.restore()
43
44 mkdir.assert_called_once_with("this/dir")
45 execute.assert_called_once_with("mongorestore -arg1 -arg2", "this/dir")
46 action_set.assert_has_calls([
47 call({"command": "mongodump -arg1 -arg2",
48 "working-dir": "this/dir"}),
49 call({"output": "output"})])
50
51if __name__ == '__main__':
52 unittest.main()
053
=== added symlink 'actions/charmhelpers'
=== target is u'../charmhelpers'
=== added file 'actions/dump'
--- actions/dump 1970-01-01 00:00:00 +0000
+++ actions/dump 2015-10-08 08:12:47 +0000
@@ -0,0 +1,4 @@
1#!/usr/bin/env python
2import backup
3
4backup.dump()
05
=== added file 'actions/restore'
--- actions/restore 1970-01-01 00:00:00 +0000
+++ actions/restore 2015-10-08 08:12:47 +0000
@@ -0,0 +1,4 @@
1#!/usr/bin/env python
2import backup
3
4backup.restore()
05
=== modified file 'charm-helpers-sync.yaml'
--- charm-helpers-sync.yaml 2015-02-25 00:24:56 +0000
+++ charm-helpers-sync.yaml 2015-10-08 08:12:47 +0000
@@ -1,5 +1,5 @@
1branch: lp:charm-helpers1branch: lp:charm-helpers
2destination: hooks/charmhelpers2destination: charmhelpers
3include:3include:
4 - core4 - core
5 - fetch5 - fetch
66
=== renamed directory 'hooks/charmhelpers' => 'charmhelpers'
=== modified file 'charmhelpers/core/hookenv.py'
--- hooks/charmhelpers/core/hookenv.py 2015-08-19 13:58:52 +0000
+++ charmhelpers/core/hookenv.py 2015-10-08 08:12:47 +0000
@@ -623,6 +623,38 @@
623 return unit_get('private-address')623 return unit_get('private-address')
624624
625625
626@cached
627def storage_get(attribute="", storage_id=""):
628 """Get storage attributes"""
629 _args = ['storage-get', '--format=json']
630 if storage_id:
631 _args.extend(('-s', storage_id))
632 if attribute:
633 _args.append(attribute)
634 try:
635 return json.loads(subprocess.check_output(_args).decode('UTF-8'))
636 except ValueError:
637 return None
638
639
640@cached
641def storage_list(storage_name=""):
642 """List the storage IDs for the unit"""
643 _args = ['storage-list', '--format=json']
644 if storage_name:
645 _args.append(storage_name)
646 try:
647 return json.loads(subprocess.check_output(_args).decode('UTF-8'))
648 except ValueError:
649 return None
650 except OSError as e:
651 import errno
652 if e.errno == errno.ENOENT:
653 # storage-list does not exist
654 return []
655 raise
656
657
626class UnregisteredHookError(Exception):658class UnregisteredHookError(Exception):
627 """Raised when an undefined hook is called"""659 """Raised when an undefined hook is called"""
628 pass660 pass
@@ -767,21 +799,23 @@
767799
768800
769def status_get():801def status_get():
770 """Retrieve the previously set juju workload state802 """Retrieve the previously set juju workload state and message
771803
772 If the status-set command is not found then assume this is juju < 1.23 and804 If the status-get command is not found then assume this is juju < 1.23 and
773 return 'unknown'805 return 'unknown', ""
806
774 """807 """
775 cmd = ['status-get']808 cmd = ['status-get', "--format=json", "--include-data"]
776 try:809 try:
777 raw_status = subprocess.check_output(cmd, universal_newlines=True)810 raw_status = subprocess.check_output(cmd)
778 status = raw_status.rstrip()
779 return status
780 except OSError as e:811 except OSError as e:
781 if e.errno == errno.ENOENT:812 if e.errno == errno.ENOENT:
782 return 'unknown'813 return ('unknown', "")
783 else:814 else:
784 raise815 raise
816 else:
817 status = json.loads(raw_status.decode("UTF-8"))
818 return (status["status"], status["message"])
785819
786820
787def translate_exc(from_exc, to_exc):821def translate_exc(from_exc, to_exc):
788822
=== modified file 'charmhelpers/core/host.py'
--- hooks/charmhelpers/core/host.py 2015-08-19 13:58:52 +0000
+++ charmhelpers/core/host.py 2015-10-08 08:12:47 +0000
@@ -63,32 +63,48 @@
63 return service_result63 return service_result
6464
6565
66def service_pause(service_name, init_dir=None):66def service_pause(service_name, init_dir="/etc/init", initd_dir="/etc/init.d"):
67 """Pause a system service.67 """Pause a system service.
6868
69 Stop it, and prevent it from starting again at boot."""69 Stop it, and prevent it from starting again at boot."""
70 if init_dir is None:
71 init_dir = "/etc/init"
72 stopped = service_stop(service_name)70 stopped = service_stop(service_name)
73 # XXX: Support systemd too71 upstart_file = os.path.join(init_dir, "{}.conf".format(service_name))
74 override_path = os.path.join(72 sysv_file = os.path.join(initd_dir, service_name)
75 init_dir, '{}.override'.format(service_name))73 if os.path.exists(upstart_file):
76 with open(override_path, 'w') as fh:74 override_path = os.path.join(
77 fh.write("manual\n")75 init_dir, '{}.override'.format(service_name))
76 with open(override_path, 'w') as fh:
77 fh.write("manual\n")
78 elif os.path.exists(sysv_file):
79 subprocess.check_call(["update-rc.d", service_name, "disable"])
80 else:
81 # XXX: Support SystemD too
82 raise ValueError(
83 "Unable to detect {0} as either Upstart {1} or SysV {2}".format(
84 service_name, upstart_file, sysv_file))
78 return stopped85 return stopped
7986
8087
81def service_resume(service_name, init_dir=None):88def service_resume(service_name, init_dir="/etc/init",
89 initd_dir="/etc/init.d"):
82 """Resume a system service.90 """Resume a system service.
8391
84 Reenable starting again at boot. Start the service"""92 Reenable starting again at boot. Start the service"""
85 # XXX: Support systemd too93 upstart_file = os.path.join(init_dir, "{}.conf".format(service_name))
86 if init_dir is None:94 sysv_file = os.path.join(initd_dir, service_name)
87 init_dir = "/etc/init"95 if os.path.exists(upstart_file):
88 override_path = os.path.join(96 override_path = os.path.join(
89 init_dir, '{}.override'.format(service_name))97 init_dir, '{}.override'.format(service_name))
90 if os.path.exists(override_path):98 if os.path.exists(override_path):
91 os.unlink(override_path)99 os.unlink(override_path)
100 elif os.path.exists(sysv_file):
101 subprocess.check_call(["update-rc.d", service_name, "enable"])
102 else:
103 # XXX: Support SystemD too
104 raise ValueError(
105 "Unable to detect {0} as either Upstart {1} or SysV {2}".format(
106 service_name, upstart_file, sysv_file))
107
92 started = service_start(service_name)108 started = service_start(service_name)
93 return started109 return started
94110
95111
=== modified file 'charmhelpers/core/hugepage.py'
--- hooks/charmhelpers/core/hugepage.py 2015-08-19 13:58:52 +0000
+++ charmhelpers/core/hugepage.py 2015-10-08 08:12:47 +0000
@@ -25,11 +25,13 @@
25 fstab_mount,25 fstab_mount,
26 mkdir,26 mkdir,
27)27)
28from charmhelpers.core.strutils import bytes_from_string
29from subprocess import check_output
2830
2931
30def hugepage_support(user, group='hugetlb', nr_hugepages=256,32def hugepage_support(user, group='hugetlb', nr_hugepages=256,
31 max_map_count=65536, mnt_point='/run/hugepages/kvm',33 max_map_count=65536, mnt_point='/run/hugepages/kvm',
32 pagesize='2MB', mount=True):34 pagesize='2MB', mount=True, set_shmmax=False):
33 """Enable hugepages on system.35 """Enable hugepages on system.
3436
35 Args:37 Args:
@@ -49,6 +51,11 @@
49 'vm.max_map_count': max_map_count,51 'vm.max_map_count': max_map_count,
50 'vm.hugetlb_shm_group': gid,52 'vm.hugetlb_shm_group': gid,
51 }53 }
54 if set_shmmax:
55 shmmax_current = int(check_output(['sysctl', '-n', 'kernel.shmmax']))
56 shmmax_minsize = bytes_from_string(pagesize) * nr_hugepages
57 if shmmax_minsize > shmmax_current:
58 sysctl_settings['kernel.shmmax'] = shmmax_minsize
52 sysctl.create(yaml.dump(sysctl_settings), '/etc/sysctl.d/10-hugepage.conf')59 sysctl.create(yaml.dump(sysctl_settings), '/etc/sysctl.d/10-hugepage.conf')
53 mkdir(mnt_point, owner='root', group='root', perms=0o755, force=False)60 mkdir(mnt_point, owner='root', group='root', perms=0o755, force=False)
54 lfstab = fstab.Fstab()61 lfstab = fstab.Fstab()
5562
=== added file 'charmhelpers/core/kernel.py'
--- charmhelpers/core/kernel.py 1970-01-01 00:00:00 +0000
+++ charmhelpers/core/kernel.py 2015-10-08 08:12:47 +0000
@@ -0,0 +1,68 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright 2014-2015 Canonical Limited.
5#
6# This file is part of charm-helpers.
7#
8# charm-helpers is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Lesser General Public License version 3 as
10# published by the Free Software Foundation.
11#
12# charm-helpers is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Lesser General Public License for more details.
16#
17# You should have received a copy of the GNU Lesser General Public License
18# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
19
20__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
21
22from charmhelpers.core.hookenv import (
23 log,
24 INFO
25)
26
27from subprocess import check_call, check_output
28import re
29
30
31def modprobe(module, persist=True):
32 """Load a kernel module and configure for auto-load on reboot."""
33 cmd = ['modprobe', module]
34
35 log('Loading kernel module %s' % module, level=INFO)
36
37 check_call(cmd)
38 if persist:
39 with open('/etc/modules', 'r+') as modules:
40 if module not in modules.read():
41 modules.write(module)
42
43
44def rmmod(module, force=False):
45 """Remove a module from the linux kernel"""
46 cmd = ['rmmod']
47 if force:
48 cmd.append('-f')
49 cmd.append(module)
50 log('Removing kernel module %s' % module, level=INFO)
51 return check_call(cmd)
52
53
54def lsmod():
55 """Shows what kernel modules are currently loaded"""
56 return check_output(['lsmod'],
57 universal_newlines=True)
58
59
60def is_module_loaded(module):
61 """Checks if a kernel module is already loaded"""
62 matches = re.findall('^%s[ ]+' % module, lsmod(), re.M)
63 return len(matches) > 0
64
65
66def update_initramfs(version='all'):
67 """Updates an initramfs image"""
68 return check_call(["update-initramfs", "-k", version, "-u"])
069
=== modified file 'charmhelpers/core/strutils.py'
--- hooks/charmhelpers/core/strutils.py 2015-08-19 13:58:52 +0000
+++ charmhelpers/core/strutils.py 2015-10-08 08:12:47 +0000
@@ -18,6 +18,7 @@
18# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.18# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
1919
20import six20import six
21import re
2122
2223
23def bool_from_string(value):24def bool_from_string(value):
@@ -40,3 +41,32 @@
4041
41 msg = "Unable to interpret string value '%s' as boolean" % (value)42 msg = "Unable to interpret string value '%s' as boolean" % (value)
42 raise ValueError(msg)43 raise ValueError(msg)
44
45
46def bytes_from_string(value):
47 """Interpret human readable string value as bytes.
48
49 Returns int
50 """
51 BYTE_POWER = {
52 'K': 1,
53 'KB': 1,
54 'M': 2,
55 'MB': 2,
56 'G': 3,
57 'GB': 3,
58 'T': 4,
59 'TB': 4,
60 'P': 5,
61 'PB': 5,
62 }
63 if isinstance(value, six.string_types):
64 value = six.text_type(value)
65 else:
66 msg = "Unable to interpret non-string value '%s' as boolean" % (value)
67 raise ValueError(msg)
68 matches = re.match("([0-9]+)([a-zA-Z]+)", value)
69 if not matches:
70 msg = "Unable to interpret string value '%s' as bytes" % (value)
71 raise ValueError(msg)
72 return int(matches.group(1)) * (1024 ** BYTE_POWER[matches.group(2)])
4373
=== added symlink 'hooks/charmhelpers'
=== target is u'../charmhelpers'

Subscribers

People subscribed via source and target branches