diff --git a/ceph/python-cephclient/centos/build_srpm.data b/ceph/python-cephclient/centos/build_srpm.data new file mode 100644 index 00000000..42cbb465 --- /dev/null +++ b/ceph/python-cephclient/centos/build_srpm.data @@ -0,0 +1,6 @@ +CLIENT_NAME=python-cephclient +CLIENT_VER=v0.1.0.5 + +COPY_LIST="$CGCS_BASE/downloads/$CLIENT_NAME-$CLIENT_VER.tar.gz $PKG_BASE/$CLIENT_NAME/*" + +TIS_PATCH_VER=2 diff --git a/ceph/python-cephclient/centos/python-cephclient.spec b/ceph/python-cephclient/centos/python-cephclient.spec new file mode 100644 index 00000000..9c1cd22b --- /dev/null +++ b/ceph/python-cephclient/centos/python-cephclient.spec @@ -0,0 +1,56 @@ +%{!?_licensedir:%global license %%doc} +%global pypi_name python-cephclient + +Name: python-cephclient +Version: 0.1.0.5 +Release: 0%{?_tis_dist}.%{tis_patch_ver} +Summary: python-cephclient + +License: Apache-2.0 +URL: https://github.com/dmsimard/python-cephclient +Group: devel/python +Packager: Wind River + +Source0: %{pypi_name}-v%{version}.tar.gz + +Patch0: fix-osd-crush-remove.patch +Patch1: set-default-endpoint.patch +Patch2: 0001-US63903-Ceph-Rebase-Update-REST-API-to-0.94.2.patch +Patch3: add-osd-get-pool-quota.patch +Patch4: 0001-US70398-Ceph-Rebase-Update-REST-API-to-0.94.5.patch +Patch5: fix-osd-tier-add.patch +Patch6: US92424-Ceph-Rebase-Update-REST-API-to-10.2.4.patch + +BuildArch: noarch + +BuildRequires: python +BuildRequires: ceph + +Requires: python + +Provides: python-cephclient + +%description +Client library for the Ceph REST API + +%prep +%autosetup -p 1 -n %{pypi_name}-%{version} + +# Remove bundled egg-info +rm -rf %{pypi_name}.egg-info + +# Let RPM handle the dependencies +rm -f requirements.txt + +%build +%{__python2} setup.py build + +%install +%{__python2} setup.py install --skip-build --root %{buildroot} + +%files +%doc README.rst +%license LICENSE +%{python2_sitelib}/cephclient +%{python2_sitelib}/*.egg-info + diff --git a/ceph/python-cephclient/python-cephclient/0001-US63903-Ceph-Rebase-Update-REST-API-to-0.94.2.patch b/ceph/python-cephclient/python-cephclient/0001-US63903-Ceph-Rebase-Update-REST-API-to-0.94.2.patch new file mode 100644 index 00000000..d2fc9b65 --- /dev/null +++ b/ceph/python-cephclient/python-cephclient/0001-US63903-Ceph-Rebase-Update-REST-API-to-0.94.2.patch @@ -0,0 +1,220 @@ +From 016ebffad6c953cf51c538cc8c45edf56e681515 Mon Sep 17 00:00:00 2001 +From: Robert Church +Date: Fri, 21 Aug 2015 13:05:18 -0500 +Subject: [PATCH] US63903: Ceph Rebase - Update REST API to 0.94.2 + +This updates the existing REST APIs to correspond to what in required by +Ceph 0.94.2 (Hammer LTS) +--- + cephclient/wrapper.py | 134 +++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 95 insertions(+), 39 deletions(-) + +diff --git a/cephclient/wrapper.py b/cephclient/wrapper.py +index 8f583a5..926eb7f 100644 +--- a/cephclient/wrapper.py ++++ b/cephclient/wrapper.py +@@ -335,8 +335,12 @@ class CephWrapper(client.CephClient): + def osd_crush_dump(self, **kwargs): + return self.get('osd/crush/dump', **kwargs) + +- def osd_crush_rule_dump(self, **kwargs): +- return self.get('osd/crush/rule/dump', **kwargs) ++ def osd_crush_rule_dump(self, name=None, **kwargs): ++ if name is not None: ++ return self.get('osd/crush/rule/dump?name={0}' ++ .format(name), **kwargs) ++ else: ++ return self.get('osd/crush/rule/dump', **kwargs) + + def osd_crush_rule_list(self, **kwargs): + return self.get('osd/crush/rule/list', **kwargs) +@@ -450,7 +454,7 @@ class CephWrapper(client.CephClient): + .format(name, args), **kwargs) + + def osd_crush_remove(self, name, ancestor=None, **kwargs): +- if ancestor: ++ if ancestor is not None: + return self.put('osd/crush/remove?name={0}&ancestor={1}' + .format(name, ancestor), **kwargs) + else: +@@ -462,29 +466,43 @@ class CephWrapper(client.CephClient): + .format(name, weight), **kwargs) + + def osd_crush_rm(self, name, ancestor, **kwargs): +- return self.put('osd/crush/rm?name={0}&ancestor={1}' +- .format(name, ancestor), **kwargs) ++ if ancestor is not None: ++ return self.put('osd/crush/rm?name={0}&ancestor={1}' ++ .format(name, ancestor), **kwargs) ++ else: ++ return self.put('osd/crush/rm?name={0}' ++ .format(name), **kwargs) + +- def osd_crush_rule_create_simple(self, name, root, type, **kwargs): +- return self.put( +- 'osd/crush/rule/create-simple?name={0}&root={1}&type={2}' +- .format(name, root, type), **kwargs) ++ def osd_crush_rule_create_simple(self, name, root, ++ type, mode=None, **kwargs): ++ if mode is not None: ++ return self.put( ++ 'osd/crush/rule/create-simple?name={0}&root={1}&type={2}' ++ '&mode={3}'.format(name, root, type, mode), **kwargs) ++ else: ++ return self.put( ++ 'osd/crush/rule/create-simple?name={0}&root={1}&type={2}' ++ .format(name, root, type), **kwargs) + + def osd_crush_rule_rm(self, name, **kwargs): + return self.put('osd/crush/rule/rm?name={0}' + .format(name), **kwargs) + +- def osd_crush_set(self, id, name, weight, args, **kwargs): ++ def osd_crush_set(self, id, weight, args, **kwargs): + return self.put('osd/crush/set?id={0}&weight={1}&args={2}' +- .format(id, name, weight, args), **kwargs) ++ .format(id, weight, args), **kwargs) + + def osd_crush_tunables(self, profile, **kwargs): + return self.put('osd/crush/tunables?profile={0}' + .format(profile), **kwargs) + +- def osd_crush_unlink(self, name, ancestor, **kwargs): +- return self.put('osd/crush/unlink?name={0}&ancestor={1}' +- .format(name, ancestor), **kwargs) ++ def osd_crush_unlink(self, name, ancestor=None, **kwargs): ++ if ancestor is not None: ++ return self.put('osd/crush/unlink?name={0}&ancestor={1}' ++ .format(name, ancestor), **kwargs) ++ else: ++ return self.put('osd/crush/unlink?name={0}' ++ .format(name), **kwargs) + + def osd_deep_scrub(self, who, **kwargs): + return self.put('osd/deep-scrub?who={0}' +@@ -498,22 +516,44 @@ class CephWrapper(client.CephClient): + return self.put('osd/in?ids={0}' + .format(ids), **kwargs) + +- def osd_lost(self, id, sure, **kwargs): +- return self.put('osd/lost?id={0}&sure={1}' +- .format(id, sure), **kwargs) ++ def osd_lost(self, id, sure=None, **kwargs): ++ if sure is not None: ++ return self.put('osd/lost?id={0}&sure={1}' ++ .format(id, sure), **kwargs) ++ else: ++ return self.put('osd/lost?id={0}' ++ .format(id), **kwargs) + + def osd_out(self, ids, **kwargs): + return self.put('osd/out?ids={0}' + .format(ids), **kwargs) + +- def osd_pool_create(self, pool, pg_num, pgp_num, properties, **kwargs): +- return self.put( +- 'osd/pool/create?pool={0}&pg_num={1}&pgp_num={2}&properties={3}' +- .format(pool, pg_num, pgp_num, properties), **kwargs) +- +- def osd_pool_delete(self, pool, sure, **kwargs): +- return self.put('osd/pool/delete?pool={0}&sure={1}' +- .format(pool, sure), **kwargs) ++ def osd_pool_create(self, pool, pg_num, pgp_num, pool_type=None, ++ erasure_code_profile=None, ruleset=None, ++ expected_num_objects=None, **kwargs): ++ request = [] ++ request.append('osd/pool/create?pool={0}&pg_num={1}&pgp_num={2}' ++ .format(pool, pg_num, pgp_num)) ++ if pool_type is not None: ++ request.append('&pool_type={0}'.format(pool_type)) ++ if erasure_code_profile is not None: ++ request.append('&erasure_code_profile={0}' ++ .format(erasure_code_profile)) ++ if ruleset is not None: ++ request.append('&ruleset={0}'.format(ruleset)) ++ if expected_num_objects is not None: ++ request.append('&expected_num_objects={0}' ++ .format(expected_num_objects)) ++ return self.put(''.join(request), **kwargs) ++ ++ def osd_pool_delete(self, pool, pool2=None, sure=None, **kwargs): ++ request = [] ++ request.append('osd/pool/delete?pool={0}'.format(pool)) ++ if pool2 is not None: ++ request.append('&pool2={0}'.format(pool2)) ++ if sure is not None: ++ request.append('&sure={0}'.format(sure)) ++ return self.put(''.join(request), **kwargs) + + def osd_pool_param(self, pool, var, **kwargs): + return self.put('osd/pool/get?pool={0}&var={1}' +@@ -531,13 +571,17 @@ class CephWrapper(client.CephClient): + return self.put('osd/pool/rmsnap?pool={0}&snap={1}' + .format(pool, snap), **kwargs) + +- def osd_set_pool_param(self, pool, var, **kwargs): +- return self.put('osd/pool/set?pool={0}&var={1}' +- .format(pool, var), **kwargs) ++ def osd_set_pool_param(self, pool, var, val, force=None, **kwargs): ++ if force is not None: ++ return self.put('osd/pool/set?pool={0}&var={1}&val={2}&force={3}' ++ .format(pool, var, val, force), **kwargs) ++ else: ++ return self.put('osd/pool/set?pool={0}&var={1}&val={2}' ++ .format(pool, var, val), **kwargs) + +- def osd_set_pool_quota(self, pool, field, **kwargs): +- return self.put('osd/pool/set-quota?pool={0}&field={1}' +- .format(pool, field), **kwargs) ++ def osd_set_pool_quota(self, pool, field, val, **kwargs): ++ return self.put('osd/pool/set-quota?pool={0}&field={1}&val={2}' ++ .format(pool, field, val), **kwargs) + + def osd_repair(self, pool, who, **kwargs): + return self.put('osd/repair?who={0}' +@@ -571,9 +615,14 @@ class CephWrapper(client.CephClient): + return self.put('osd/thrash?num_epochs={0}' + .format(num_epochs), **kwargs) + +- def osd_tier_add(self, pool, tierpool, **kwargs): +- return self.put('osd/tier/add?pool={0}&tierpool={1}' +- .format(pool, tierpool), **kwargs) ++ def osd_tier_add(self, pool, tierpool, force_notempty=None, **kwargs): ++ if force_notempty is not None: ++ return self.put('osd/tier/add?pool={0}&tierpool={1}' ++ '&force_notempty={2}' ++ .format(pool, tierpool, force_notempty), **kwargs) ++ else: ++ return self.put('osd/tier/add?pool={0}&tierpool={1}' ++ .format(pool, tierpool), **kwargs) + + def osd_tier_cachemode(self, pool, mode, **kwargs): + return self.put('osd/tier/cache-mode?pool={0}&mode={1}' +@@ -621,12 +670,19 @@ class CephWrapper(client.CephClient): + def pg_dump_pools_json(self, **kwargs): + return self.get('pg/dump_pools_json', **kwargs) + +- def pg_dump_stuck(self, stuckops=None, **kwargs): ++ def pg_dump_stuck(self, stuckops=None, threshold=None, **kwargs): ++ request = [] ++ request.append('pg/dump_stuck') + if stuckops is not None: +- return self.get('pg/dump_stuck?stuckops={0}' +- .format(stuckops), **kwargs) +- else: +- return self.get('pg/dump_stuck', **kwargs) ++ request.append('?stuckops={0}'.format(stuckops)) ++ if threshold is not None: ++ if stuckops is not None: ++ request.append('&') ++ else: ++ request.append('?') ++ request.append('threshold={0}'.format(threshold)) ++ ++ return self.get(''.join(request), **kwargs) + + def pg_getmap(self, **kwargs): + kwargs['supported_body_types'] = ['binary'] +-- +2.5.0 + diff --git a/ceph/python-cephclient/python-cephclient/0001-US70398-Ceph-Rebase-Update-REST-API-to-0.94.5.patch b/ceph/python-cephclient/python-cephclient/0001-US70398-Ceph-Rebase-Update-REST-API-to-0.94.5.patch new file mode 100644 index 00000000..15d01089 --- /dev/null +++ b/ceph/python-cephclient/python-cephclient/0001-US70398-Ceph-Rebase-Update-REST-API-to-0.94.5.patch @@ -0,0 +1,475 @@ +From 2253242390ed6dfd1206ae2743ccab4c28437d13 Mon Sep 17 00:00:00 2001 +From: Robert Church +Date: Tue, 24 Nov 2015 20:37:39 -0600 +Subject: [PATCH] US70398: Ceph Rebase - Update REST API to 0.94.5 + +Add support for all APIs currently present in the Ceph REST API. This +provides a version 0.94.5 compliant client and include client calls that +were present previously but never added to the python-cephclient. +--- + cephclient/wrapper.py | 281 +++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 269 insertions(+), 12 deletions(-) + +diff --git a/cephclient/wrapper.py b/cephclient/wrapper.py +index 867b68b..871b53a 100644 +--- a/cephclient/wrapper.py ++++ b/cephclient/wrapper.py +@@ -58,6 +58,9 @@ class CephWrapper(client.CephClient): + def status(self, **kwargs): + return self.get('status', **kwargs) + ++ def version(self, **kwargs): ++ return self.get('version', **kwargs) ++ + ### + # root PUT calls + ### +@@ -83,6 +86,16 @@ class CephWrapper(client.CephClient): + def scrub(self, **kwargs): + return self.put('scrub', **kwargs) + ++ def sync(self, validate1=None, validate2=None, **kwargs): ++ request = [] ++ request.append('sync/force') ++ if validate1 is not None: ++ request.append('?validate1={0}'.format(validate1)) ++ if validate2 is not None: ++ request.append('validate2={0}'.format(validate2)) ++ ++ return self.put(''.join(request), **kwargs) ++ + def tell(self, target, args, **kwargs): + return self.put('tell?target={0}&args={1}' + .format(target, args), **kwargs) +@@ -191,6 +204,44 @@ class CephWrapper(client.CephClient): + return self.get('config-key/list', **kwargs) + + ### ++ # config-key PUT calls ++ ### ++ def config_key_del(self, key, **kwargs): ++ return self.put('config-key/del?key={0}' ++ .format(key), **kwargs) ++ ++ def config_key_put(self, key, val, **kwargs): ++ return self.put('config-key/put?key={0}&val={1}' ++ .format(key, val), **kwargs) ++ ++ ### ++ # fs GET calls ++ ### ++ def fs_ls(self, **kwargs): ++ return self.get('fs/ls', **kwargs) ++ ++ ### ++ # fs PUT calls ++ ### ++ def fs_new(self, fs_name, metadata, data, **kwargs): ++ return self.put('fs/new?fs_name={0}&metadata={1}&data={2}' ++ .format(fs_name, metadata, data), **kwargs) ++ ++ def fs_reset(self, fs_name, sure=None, **kwargs): ++ request = [] ++ request.append('fs/reset?fs_name={0}'.format(fs_name)) ++ if sure is not None: ++ request.append('&sure={0}'.format(sure)) ++ return self.put(''.join(request), **kwargs) ++ ++ def fs_rm(self, fs_name, sure=None, **kwargs): ++ request = [] ++ request.append('fs/rm?fs_name={0}'.format(fs_name)) ++ if sure is not None: ++ request.append('&sure={0}'.format(sure)) ++ return self.put(''.join(request), **kwargs) ++ ++ ### + # mds GET calls + ### + def mds_compat_show(self, **kwargs): +@@ -244,9 +295,13 @@ class CephWrapper(client.CephClient): + return self.put('mds/fail?who={0}' + .format(who), **kwargs) + +- def mds_newfs(self, metadata, data, sure, **kwargs): +- return self.put('mds/newfs?metadata={0}&data={1}&sure={2}' +- .format(metadata, data, sure), **kwargs) ++ def mds_newfs(self, metadata, data, sure=None, **kwargs): ++ if sure is not None: ++ return self.put('mds/newfs?metadata={0}&data={1}&sure={2}' ++ .format(metadata, data, sure), **kwargs) ++ else: ++ return self.put('mds/newfs?metadata={0}&data={1}' ++ .format(metadata, data), **kwargs) + + def mds_remove_data_pool(self, pool, **kwargs): + return self.put('mds/remove_data_pool?pool={0}' +@@ -260,11 +315,29 @@ class CephWrapper(client.CephClient): + return self.put('mds/rmfailed?who={0}' + .format(who), **kwargs) + +- def mds_set_allow_new_snaps(self, sure, **kwargs): +- """ +- mds/set?key=allow_new_snaps&sure= +- """ +- raise exceptions.FunctionNotImplemented() ++ def mds_set_max_file_size(self, val, confirm=None, **kwargs): ++ if confirm is not None: ++ return self.put('mds/set?var=max_file_size?val={0}&confirm={1}' ++ .format(val, confirm), **kwargs) ++ else: ++ return self.put('mds/set?var=max_file_size?val={0}' ++ .format(val), **kwargs) ++ ++ def mds_set_allow_new_snaps(self, val, confirm=None, **kwargs): ++ if confirm is not None: ++ return self.put('mds/set?var=allow_new_snaps?val={0}&confirm={1}' ++ .format(val, confirm), **kwargs) ++ else: ++ return self.put('mds/set?var=allow_new_snaps?val={0}' ++ .format(val), **kwargs) ++ ++ def mds_set_inline_data(self, val, confirm=None, **kwargs): ++ if confirm is not None: ++ return self.put('mds/set?var=inline_data?val={0}&confirm={1}' ++ .format(val, confirm), **kwargs) ++ else: ++ return self.put('mds/set?var=inline_data?val={0}' ++ .format(val), **kwargs) + + def mds_set_max_mds(self, maxmds, **kwargs): + return self.put('mds/set_max_mds?maxmds={0}' +@@ -332,6 +405,9 @@ class CephWrapper(client.CephClient): + def osd_blacklist_ls(self, **kwargs): + return self.get('osd/blacklist/ls', **kwargs) + ++ def osd_blocked_by(self, **kwargs): ++ return self.get('osd/blocked-by', **kwargs) ++ + def osd_crush_dump(self, **kwargs): + return self.get('osd/crush/dump', **kwargs) + +@@ -348,6 +424,19 @@ class CephWrapper(client.CephClient): + def osd_crush_rule_ls(self, **kwargs): + return self.get('osd/crush/rule/ls', **kwargs) + ++ def osd_crush_show_tunables(self, **kwargs): ++ return self.get('osd/crush/show-tunables', **kwargs) ++ ++ def osd_crush_tree(self, **kwargs): ++ return self.get('osd/crush/tree', **kwargs) ++ ++ def osd_df(self, output_method=None, **kwargs): ++ if output_method is not None: ++ return self.get('osd/df?output_method={0}' ++ .format(output_method), **kwargs) ++ else: ++ return self.get('osd/df', **kwargs) ++ + def osd_dump(self, epoch=None, **kwargs): + if epoch is not None: + return self.get('osd/dump?epoch={0}' +@@ -355,6 +444,13 @@ class CephWrapper(client.CephClient): + else: + return self.get('osd/dump', **kwargs) + ++ def osd_erasure_code_profile_get(self, name, **kwargs): ++ return self.get('osd/erasure-code-profile/get?name={0}' ++ .format(name), **kwargs) ++ ++ def osd_erasure_code_profile_ls(self, **kwargs): ++ return self.get('osd/erasure-code-profile/ls', **kwargs) ++ + def osd_find(self, id, **kwargs): + return self.get('osd/find?id={0}' + .format(id), **kwargs) +@@ -398,9 +494,17 @@ class CephWrapper(client.CephClient): + return self.get('osd/map?pool={0}&object={1}' + .format(pool, object), **kwargs) + ++ def osd_metadata(self, id, **kwargs): ++ return self.get('osd/metadata?id={0}' ++ .format(id), **kwargs) ++ + def osd_perf(self, **kwargs): + return self.get('osd/perf', **kwargs) + ++ def osd_get_pool_param(self, pool, var, **kwargs): ++ return self.get('osd/pool/get?pool={0}&var={1}' ++ .format(pool, var), **kwargs) ++ + def osd_pool_get(self, pool, var, **kwargs): + return self.get('osd/pool/get?pool={0}&var={1}' + .format(pool, var), **kwargs) +@@ -416,6 +520,13 @@ class CephWrapper(client.CephClient): + return self.get('osd/pool/get-quota?pool={0}' + .format(pool), **kwargs) + ++ def osd_pool_ls(self, detail=None, **kwargs): ++ if detail is not None: ++ return self.get('osd/pool/ls?detail={0}' ++ .format(detail), **kwargs) ++ else: ++ return self.get('osd/pool/ls', **kwargs) ++ + def osd_stat(self, **kwargs): + return self.get('osd/stat', **kwargs) + +@@ -449,6 +560,10 @@ class CephWrapper(client.CephClient): + return self.put('osd/crush/create-or-move?id={0}&weight={1}&args={2}' + .format(id, weight, args), **kwargs) + ++ def osd_crush_get_tunable(self, tunable, **kwargs): ++ return self.put('osd/crush/get-tunable?tunable={0}' ++ .format(tunable), **kwargs) ++ + def osd_crush_link(self, name, args, **kwargs): + return self.put('osd/crush/link?name={0}&args={2}' + .format(name, args), **kwargs) +@@ -465,10 +580,21 @@ class CephWrapper(client.CephClient): + return self.put('osd/crush/remove?name={0}' + .format(name), **kwargs) + ++ def osd_crush_rename_bucket(self, srcname, dstname, **kwargs): ++ return self.put('osd/crush/rename-bucket?srcname={0}&dstname={1}' ++ .format(srcname, dstname), **kwargs) ++ + def osd_crush_reweight(self, name, weight, **kwargs): + return self.put('osd/crush/reweight?name={0}&weight={1}' + .format(name, weight), **kwargs) + ++ def osd_crush_reweight_all(self, **kwargs): ++ return self.put('osd/crush/reweight-all', **kwargs) ++ ++ def osd_crush_reweight_subtree(self, name, weight, **kwargs): ++ return self.put('osd/crush/reweight-subtree?name={0}&weight={1}' ++ .format(name, weight), **kwargs) ++ + def osd_crush_rm(self, name, ancestor, **kwargs): + if ancestor is not None: + return self.put('osd/crush/rm?name={0}&ancestor={1}' +@@ -477,6 +603,11 @@ class CephWrapper(client.CephClient): + return self.put('osd/crush/rm?name={0}' + .format(name), **kwargs) + ++ def osd_crush_rule_create_erasure(self, name, profile, **kwargs): ++ return self.put( ++ 'osd/crush/rule/create-erasure?name={0}&profile={1}' ++ .format(name, profile), **kwargs) ++ + def osd_crush_rule_create_simple(self, name, root, + type, mode=None, **kwargs): + if mode is not None: +@@ -496,6 +627,10 @@ class CephWrapper(client.CephClient): + return self.put('osd/crush/set?id={0}&weight={1}&args={2}' + .format(id, weight, args), **kwargs) + ++ def osd_crush_set_tunable(self, tunable, value, **kwargs): ++ return self.put('osd/crush/set-tunable?tunable={0}&value={1}' ++ .format(tunable), **kwargs) ++ + def osd_crush_tunables(self, profile, **kwargs): + return self.put('osd/crush/tunables?profile={0}' + .format(profile), **kwargs) +@@ -516,6 +651,18 @@ class CephWrapper(client.CephClient): + return self.put('osd/down?ids={0}' + .format(ids), **kwargs) + ++ def osd_erasure_code_profile_rm(self, name, **kwargs): ++ return self.put('osd/erasure-code-profile/rm?name={0}' ++ .format(name), **kwargs) ++ ++ def osd_erasure_code_profile_set(self, name, profile=None, **kwargs): ++ if profile is not None: ++ return self.put('osd/erasure-code-profile/set?name={0}&profile={1}' ++ .format(name, profile), **kwargs) ++ else: ++ return self.put('osd/erasure-code-profile/set?name={0}' ++ .format(name), **kwargs) ++ + def osd_in(self, ids, **kwargs): + return self.put('osd/in?ids={0}' + .format(ids), **kwargs) +@@ -532,6 +679,17 @@ class CephWrapper(client.CephClient): + return self.put('osd/out?ids={0}' + .format(ids), **kwargs) + ++ def osd_pause(self, **kwargs): ++ return self.put('osd/pause', **kwargs) ++ ++ def osd_pg_temp(self, pgid, id=None, **kwargs): ++ if id is not None: ++ return self.put('osd/pg-temp?pgid={0}&id={1}' ++ .format(pgid, id), **kwargs) ++ else: ++ return self.put('osd/pg-temp?pgid={0}' ++ .format(pgid), **kwargs) ++ + def osd_pool_create(self, pool, pg_num, pgp_num, pool_type=None, + erasure_code_profile=None, ruleset=None, + expected_num_objects=None, **kwargs): +@@ -559,10 +717,6 @@ class CephWrapper(client.CephClient): + request.append('&sure={0}'.format(sure)) + return self.put(''.join(request), **kwargs) + +- def osd_pool_param(self, pool, var, **kwargs): +- return self.put('osd/pool/get?pool={0}&var={1}' +- .format(pool, var), **kwargs) +- + def osd_pool_mksnap(self, pool, snap, **kwargs): + return self.put('osd/pool/mksnap?pool={0}&snap={1}' + .format(pool, snap), **kwargs) +@@ -583,6 +737,22 @@ class CephWrapper(client.CephClient): + return self.put('osd/pool/set?pool={0}&var={1}&val={2}' + .format(pool, var, val), **kwargs) + ++ def osd_pool_set(self, pool, var, val, force=None, **kwargs): ++ if force is not None: ++ return self.put('osd/pool/set?pool={0}&var={1}&val={2}&force={3}' ++ .format(pool, var, val, force), **kwargs) ++ else: ++ return self.put('osd/pool/set?pool={0}&var={1}&val={2}' ++ .format(pool, var, val), **kwargs) ++ ++ def osd_primary_affinity(self, id, weight, **kwargs): ++ return self.put('osd/primary-affinity?id={0}&weight={1}' ++ .format(id, weight), **kwargs) ++ ++ def osd_primary_temp(self, pgid, id, **kwargs): ++ return self.put('osd/primary-temp?pgid={0}&id={1}' ++ .format(pgid, id), **kwargs) ++ + def osd_set_pool_quota(self, pool, field, val, **kwargs): + return self.put('osd/pool/set-quota?pool={0}&field={1}&val={2}' + .format(pool, field, val), **kwargs) +@@ -595,6 +765,10 @@ class CephWrapper(client.CephClient): + return self.put('osd/reweight?id={0}&weight={1}' + .format(id, weight), **kwargs) + ++ def osd_reweight_by_pg(self, oload, pools, **kwargs): ++ return self.put('osd/reweight-by-pg?oload={0}&pools={1}' ++ .format(oload, pools), **kwargs) ++ + def osd_reweight_by_utilization(self, oload, **kwargs): + return self.put('osd/reweight-by-utilization?oload={0}' + .format(oload), **kwargs) +@@ -611,6 +785,12 @@ class CephWrapper(client.CephClient): + return self.put('osd/set?key={0}' + .format(key), **kwargs) + ++ def osd_crushmap(self, **kwargs): ++ """ ++ osd/crushmap ++ """ ++ raise exceptions.FunctionNotImplemented() ++ + def osd_setmaxosd(self, newmax, **kwargs): + return self.put('osd/setmaxosd?newmax={0}' + .format(newmax), **kwargs) +@@ -628,6 +808,11 @@ class CephWrapper(client.CephClient): + return self.put('osd/tier/add?pool={0}&tierpool={1}' + .format(pool, tierpool), **kwargs) + ++ def osd_tier_add_cache(self, pool, tierpool, size, **kwargs): ++ return self.put('osd/tier/add-cache?pool={0}&tierpool={1}' ++ '&size={2}' ++ .format(pool, tierpool, size), **kwargs) ++ + def osd_tier_cachemode(self, pool, mode, **kwargs): + return self.put('osd/tier/cache-mode?pool={0}&mode={1}' + .format(pool, mode), **kwargs) +@@ -644,6 +829,9 @@ class CephWrapper(client.CephClient): + return self.put('osd/tier/set-overlay?pool={0}&overlaypool={1}' + .format(pool, overlaypool), **kwargs) + ++ def osd_unpause(self, key, **kwargs): ++ return self.put('osd/unpause', **kwargs) ++ + def osd_unset(self, key, **kwargs): + return self.put('osd/unset?key={0}' + .format(key), **kwargs) +@@ -693,6 +881,44 @@ class CephWrapper(client.CephClient): + + return self.get('pg/getmap', **kwargs) + ++ def pg_ls(self, pool=None, states=None, **kwargs): ++ request = [] ++ request.append('pg/ls') ++ if pool is not None: ++ request.append('?pool={0}'.format(pool)) ++ if states is not None: ++ request.append('states={0}'.format(states)) ++ ++ return self.get(''.join(request), **kwargs) ++ ++ def pg_ls_by_osd(self, osd, pool=None, states=None, **kwargs): ++ request = [] ++ request.append('pg/ls-by-osd?osd={0}'.format(osd)) ++ if pool is not None: ++ request.append('?pool={0}'.format(pool)) ++ if states is not None: ++ request.append('states={0}'.format(states)) ++ ++ return self.get(''.join(request), **kwargs) ++ ++ def pg_ls_by_pool(self, poolstr, states=None, **kwargs): ++ if states is not None: ++ return self.get('pg/ls-by-pool?poolstr={0}&states={1}' ++ .format(poolstr, states), **kwargs) ++ else: ++ return self.get('pg/ls-by-pool?poolstr={0}' ++ .format(poolstr), **kwargs) ++ ++ def pg_ls_by_primary(self, osd, pool=None, states=None, **kwargs): ++ request = [] ++ request.append('pg/ls-by-primary?osd={0}'.format(osd)) ++ if pool is not None: ++ request.append('?pool={0}'.format(pool)) ++ if states is not None: ++ request.append('states={0}'.format(states)) ++ ++ return self.get(''.join(request), **kwargs) ++ + def pg_map(self, pgid, **kwargs): + return self.get('pg/map?pgid={0}' + .format(pgid), **kwargs) +@@ -701,6 +927,37 @@ class CephWrapper(client.CephClient): + return self.get('pg/stat', **kwargs) + + ### ++ # pg PUT calls ++ ### ++ ++ def pg_deep_scrub(self, pgid, **kwargs): ++ return self.put('pg/deep-scrub?pgid={0}' ++ .format(pgid), **kwargs) ++ ++ def pg_force_create_pg(self, pgid, **kwargs): ++ return self.put('pg/force_create_pg?pgid={0}' ++ .format(pgid), **kwargs) ++ ++ def pg_repair(self, pgid, **kwargs): ++ return self.put('pg/repair?pgid={0}' ++ .format(pgid), **kwargs) ++ ++ def pg_scrub(self, pgid, **kwargs): ++ return self.put('pg/scrub?pgid={0}' ++ .format(pgid), **kwargs) ++ ++ def pg_send_pg_creates(self, **kwargs): ++ return self.put('pg/send_pg_creates', **kwargs) ++ ++ def pg_set_full_ratio(self, ratio, **kwargs): ++ return self.put('pg/set_full_ratio?ratio={0}' ++ .format(ratio), **kwargs) ++ ++ def pg_set_nearfull_ratio(self, ratio, **kwargs): ++ return self.put('pg/set_nearfull_ratio?ratio={0}' ++ .format(ratio), **kwargs) ++ ++ ### + # tell GET calls + ### + def tell_debug_dump_missing(self, id, filename, **kwargs): +-- +2.5.0 + diff --git a/ceph/python-cephclient/python-cephclient/US92424-Ceph-Rebase-Update-REST-API-to-10.2.4.patch b/ceph/python-cephclient/python-cephclient/US92424-Ceph-Rebase-Update-REST-API-to-10.2.4.patch new file mode 100644 index 00000000..01660c8e --- /dev/null +++ b/ceph/python-cephclient/python-cephclient/US92424-Ceph-Rebase-Update-REST-API-to-10.2.4.patch @@ -0,0 +1,1062 @@ +--- a/cephclient/wrapper.py 2017-02-16 14:59:35.589795141 +0200 ++++ b/cephclient/wrapper.py 2017-02-16 20:15:47.543896397 +0200 +@@ -25,9 +25,6 @@ class CephWrapper(client.CephClient): + super(CephWrapper, self).__init__(**params) + self.user_agent = 'python-cephclient-wrapper' + +- ### +- # root GET calls +- ### + def df(self, detail=None, **kwargs): + if detail is not None: + return self.get('df?detail={0}' +@@ -61,9 +58,6 @@ class CephWrapper(client.CephClient): + def version(self, **kwargs): + return self.get('version', **kwargs) + +- ### +- # root PUT calls +- ### + def compact(self, **kwargs): + return self.put('compact', **kwargs) + +@@ -72,10 +66,14 @@ class CephWrapper(client.CephClient): + .format(heapcmd), **kwargs) + + def injectargs(self, injected_args, **kwargs): ++ if isinstance(injected_args, list): ++ injected_args = '&injected_args='.join(injected_args) + return self.put('injectargs?injected_args={0}' + .format(injected_args), **kwargs) + + def log(self, logtext, **kwargs): ++ if isinstance(logtext, list): ++ logtext = '&logtext='.join(logtext) + return self.put('log?logtext={0}' + .format(logtext), **kwargs) + +@@ -87,22 +85,25 @@ class CephWrapper(client.CephClient): + return self.put('scrub', **kwargs) + + def sync(self, validate1=None, validate2=None, **kwargs): ++ return self.sync_force(validate1, validate2, **kwargs) ++ ++ def sync_force(self, validate1=None, validate2=None, **kwargs): + request = [] + request.append('sync/force') + if validate1 is not None: +- request.append('?validate1={0}'.format(validate1)) ++ request.append('validate1={0}'.format(validate1)) + if validate2 is not None: + request.append('validate2={0}'.format(validate2)) +- +- return self.put(''.join(request), **kwargs) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) + + def tell(self, target, args, **kwargs): ++ if isinstance(args, list): ++ args = '&args='.join(args) + return self.put('tell?target={0}&args={1}' + .format(target, args), **kwargs) + +- ### +- # auth GET calls +- ### + def auth_export(self, entity=None, **kwargs): + if entity is not None: + return self.get('auth/export?entity={0}' +@@ -125,9 +126,10 @@ class CephWrapper(client.CephClient): + return self.get('auth/print-key?entity={0}' + .format(entity), **kwargs) + +- ### +- # auth PUT calls +- ### ++ def auth_print_key(self, entity, **kwargs): ++ return self.get('auth/print_key?entity={0}' ++ .format(entity), **kwargs) ++ + """ + caps dictionary format: + caps = { +@@ -136,62 +138,50 @@ class CephWrapper(client.CephClient): + ... + } + """ +- def auth_add(self, entity, caps={}, file=None, **kwargs): +- # XXX-TODO: Implement file input +- full_caps = list() ++ def auth_add(self, entity, caps={}, **kwargs): + if caps: +- for key in caps: +- permissions = caps[key].replace(' ', '+') +- full_caps.append('&caps={0}&caps={1}' +- .format(key, permissions)) +- +- return self.put('auth/add?entity={0}{1}' +- .format(entity, ''.join(full_caps)), **kwargs) ++ caps = '&caps='.join(['{}&caps={}'.format(k, v) for (k, v) in caps.items()]).replace(' ', '+') ++ return self.put('auth/add?entity={0}&caps={1}' ++ .format(entity, caps), **kwargs) ++ else: ++ return self.put('auth/add?entity={0}' ++ .format(entity), **kwargs) + +- def auth_caps(self, entity, caps={}, **kwargs): +- full_caps = list() ++ def auth_caps(self, entity, caps, **kwargs): + if caps: +- for key in caps: +- permissions = caps[key].replace(' ', '+') +- full_caps.append('&caps={0}&caps={1}' +- .format(key, permissions)) +- +- return self.put('auth/caps?entity={0}{1}' +- .format(entity, ''.join(full_caps)), **kwargs) ++ caps = '&caps='.join(['{}&caps={}'.format(k, v) for (k, v) in caps.items()]).replace(' ', '+') ++ return self.put('auth/caps?entity={0}&caps={1}' ++ .format(entity, caps), **kwargs) + + def auth_del(self, entity, **kwargs): + return self.put('auth/del?entity={0}' + .format(entity), **kwargs) + +- def auth_get_or_create(self, entity, caps={}, file=None, **kwargs): +- # XXX-TODO: Implement file input +- full_caps = list() ++ def auth_get_or_create(self, entity, caps={}, **kwargs): + if caps: +- for key in caps: +- permissions = caps[key].replace(' ', '+') +- full_caps.append('&caps={0}&caps={1}'.format(key, permissions)) +- +- return self.put('auth/get-or-create?entity={0}{1}' +- .format(entity, ''.join(full_caps)), **kwargs) ++ caps = '&caps='.join(['{}&caps={}'.format(k, v) for (k, v) in caps.items()]).replace(' ', '+') ++ return self.put('auth/get-or-create?entity={0}&caps={1}' ++ .format(entity, caps), **kwargs) ++ else: ++ return self.put('auth/get-or-create?entity={0}' ++ .format(entity), **kwargs) + + def auth_get_or_create_key(self, entity, caps={}, **kwargs): +- # XXX-TODO: Implement file input +- full_caps = list() +- if caps: +- for key in caps: +- permissions = caps[key].replace(' ', '+') +- full_caps.append('&caps={0}&caps={1}'.format(key, permissions)) +- +- return self.put('auth/get-or-create-key?entity={0}{1}' +- .format(entity, ''.join(full_caps)), **kwargs) +- +- def auth_import(self, file): +- # XXX-TODO: Implement file input +- raise exceptions.FunctionNotImplemented() +- +- ### +- # config-key GET calls +- ### ++ if caps is not None: ++ caps = '&caps='.join(['{}&caps={}'.format(k, v) for (k, v) in caps.items()]).replace(' ', '+') ++ return self.put('auth/get-or-create-key?entity={0}&caps={1}' ++ .format(entity, caps), **kwargs) ++ else: ++ return self.put('auth/get-or-create-key?entity={0}' ++ .format(entity), **kwargs) ++ ++ def auth_import(self, **kwargs): ++ return self.put('auth/import', **kwargs) ++ ++ def auth_rm(self, entity, **kwargs): ++ return self.put('auth/rm?entity={0}' ++ .format(entity), **kwargs) ++ + def config_key_exists(self, key, **kwargs): + return self.get('config-key/exists?key={0}' + .format(key), **kwargs) +@@ -203,47 +193,84 @@ class CephWrapper(client.CephClient): + def config_key_list(self, **kwargs): + return self.get('config-key/list', **kwargs) + +- ### +- # config-key PUT calls +- ### + def config_key_del(self, key, **kwargs): + return self.put('config-key/del?key={0}' + .format(key), **kwargs) + +- def config_key_put(self, key, val, **kwargs): +- return self.put('config-key/put?key={0}&val={1}' +- .format(key, val), **kwargs) +- +- ### +- # fs GET calls +- ### ++ def config_key_put(self, key, val=None, **kwargs): ++ if val is not None: ++ return self.put('config-key/put?key={0}&val={1}' ++ .format(key, val), **kwargs) ++ else: ++ return self.put('config-key/put?key={0}' ++ .format(key), **kwargs) ++ ++ def config_key_rm(self, key, **kwargs): ++ return self.put('config-key/rm?key={0}' ++ .format(key), **kwargs) ++ + def fs_ls(self, **kwargs): + return self.get('fs/ls', **kwargs) + +- ### +- # fs PUT calls +- ### + def fs_new(self, fs_name, metadata, data, **kwargs): + return self.put('fs/new?fs_name={0}&metadata={1}&data={2}' + .format(fs_name, metadata, data), **kwargs) + + def fs_reset(self, fs_name, sure=None, **kwargs): +- request = [] +- request.append('fs/reset?fs_name={0}'.format(fs_name)) + if sure is not None: +- request.append('&sure={0}'.format(sure)) +- return self.put(''.join(request), **kwargs) ++ return self.put('fs/reset?fs_name={0}&sure={1}' ++ .format(fs_name, sure), **kwargs) ++ else: ++ return self.put('fs/reset?fs_name={0}' ++ .format(fs_name), **kwargs) + + def fs_rm(self, fs_name, sure=None, **kwargs): +- request = [] +- request.append('fs/rm?fs_name={0}'.format(fs_name)) + if sure is not None: +- request.append('&sure={0}'.format(sure)) +- return self.put(''.join(request), **kwargs) ++ return self.put('fs/rm?fs_name={0}&sure={1}' ++ .format(fs_name, sure), **kwargs) ++ else: ++ return self.put('fs/rm?fs_name={0}' ++ .format(fs_name), **kwargs) ++ ++ def fs_add_data_pool(self, fs_name, pool, **kwargs): ++ return self.put('fs/add_data_pool?fs_name={0}&pool={1}' ++ .format(fs_name, pool), **kwargs) ++ ++ def fs_dump(self, epoch=None, **kwargs): ++ if epoch is not None: ++ return self.get('fs/dump?epoch={0}' ++ .format(epoch), **kwargs) ++ else: ++ return self.get('fs/dump', **kwargs) ++ ++ def fs_flag_set(self, flag_name, val, confirm=None, **kwargs): ++ if confirm is not None: ++ return self.put('fs/flag/set?flag_name={0}&val={1}&confirm={2}' ++ .format(flag_name, val, confirm), **kwargs) ++ else: ++ return self.put('fs/flag/set?flag_name={0}&val={1}' ++ .format(flag_name, val), **kwargs) ++ ++ def fs_get(self, fs_name, **kwargs): ++ return self.get('fs/get?fs_name={0}' ++ .format(fs_name), **kwargs) ++ ++ def fs_rm_data_pool(self, fs_name, pool, **kwargs): ++ return self.put('fs/rm_data_pool?fs_name={0}&pool={1}' ++ .format(fs_name, pool), **kwargs) ++ ++ def fs_set(self, fs_name, var, val, confirm=None, **kwargs): ++ if confirm is not None: ++ return self.put('fs/set?fs_name={0}&var={1}&val={2}&confirm={3}' ++ .format(fs_name, var, val, confirm), **kwargs) ++ else: ++ return self.put('fs/set?fs_name={0}&var={1}&val={2}' ++ .format(fs_name, var, val), **kwargs) ++ ++ def fs_set_default(self, fs_name, **kwargs): ++ return self.put('fs/set_default?fs_name={0}' ++ .format(fs_name), **kwargs) + +- ### +- # mds GET calls +- ### + def mds_compat_show(self, **kwargs): + return self.get('mds/compat/show', **kwargs) + +@@ -266,9 +293,6 @@ class CephWrapper(client.CephClient): + def mds_stat(self, **kwargs): + return self.get('mds/stat', **kwargs) + +- ### +- # mds PUT calls +- ### + def mds_add_data_pool(self, pool, **kwargs): + return self.put('mds/add_data_pool?pool={0}' + .format(pool), **kwargs) +@@ -307,63 +331,69 @@ class CephWrapper(client.CephClient): + return self.put('mds/remove_data_pool?pool={0}' + .format(pool), **kwargs) + +- def mds_rm(self, gid, who, **kwargs): +- return self.put('mds/rm?gid={0}&who={1}' +- .format(gid, who), **kwargs) ++ def mds_rm(self, gid, **kwargs): ++ return self.put('mds/rm?gid={0}' ++ .format(gid), **kwargs) + +- def mds_rmfailed(self, who, **kwargs): +- return self.put('mds/rmfailed?who={0}' +- .format(who), **kwargs) +- +- def mds_set_max_file_size(self, val, confirm=None, **kwargs): ++ def mds_rmfailed(self, who, confirm=None, **kwargs): + if confirm is not None: +- return self.put('mds/set?var=max_file_size?val={0}&confirm={1}' +- .format(val, confirm), **kwargs) ++ return self.put('mds/rmfailed?who={0}&confirm={1}' ++ .format(who, confirm), **kwargs) + else: +- return self.put('mds/set?var=max_file_size?val={0}' +- .format(val), **kwargs) ++ return self.put('mds/rmfailed?who={0}' ++ .format(who), **kwargs) ++ ++ def mds_set_max_file_size(self, val, confirm=None, **kwargs): ++ return self.mds_set(self, 'max_file_size', val, confirm=None, **kwargs) + + def mds_set_allow_new_snaps(self, val, confirm=None, **kwargs): +- if confirm is not None: +- return self.put('mds/set?var=allow_new_snaps?val={0}&confirm={1}' +- .format(val, confirm), **kwargs) +- else: +- return self.put('mds/set?var=allow_new_snaps?val={0}' +- .format(val), **kwargs) ++ return self.mds_set(self, 'allow_new_snaps', val, confirm=None, **kwargs) + + def mds_set_inline_data(self, val, confirm=None, **kwargs): +- if confirm is not None: +- return self.put('mds/set?var=inline_data?val={0}&confirm={1}' +- .format(val, confirm), **kwargs) +- else: +- return self.put('mds/set?var=inline_data?val={0}' +- .format(val), **kwargs) ++ return self.mds_set(self, 'inline_data', val, confirm=None, **kwargs) + + def mds_set_max_mds(self, maxmds, **kwargs): + return self.put('mds/set_max_mds?maxmds={0}' + .format(maxmds), **kwargs) + +- def mds_setmap(self, epoch, **kwargs): +- return self.put('mds/setmap?epoch={0}' +- .format(epoch), **kwargs) ++ # mds_setmap() not defined in new api + + def mds_stop(self, who, **kwargs): + return self.put('mds/stop?who={0}' + .format(who), **kwargs) + + def mds_tell(self, who, args, **kwargs): ++ if isinstance(args, list): ++ args = '&args='.join(args) + return self.put('mds/tell?who={0}&args={1}' + .format(who, args), **kwargs) + +- def mds_unset_allow_new_snaps(self, sure, **kwargs): +- """ +- mds/unset?key=allow_new_snaps&sure= +- """ +- raise exceptions.FunctionNotImplemented() +- +- ### +- # mon GET calls +- ### ++ # mds_unset_allow_new_snaps() not defined in new api ++ ++ def mds_metadata(self, who, **kwargs): ++ return self.get('mds/metadata?who={0}' ++ .format(who), **kwargs) ++ ++ def mds_repaired(self, rank, **kwargs): ++ return self.put('mds/repaired?rank={0}' ++ .format(rank), **kwargs) ++ ++ def mds_rm_data_pool(self, pool, **kwargs): ++ return self.put('mds/rm_data_pool?pool={0}' ++ .format(pool), **kwargs) ++ ++ def mds_set(self, var, val, confirm=None, **kwargs): ++ if confirm is not None: ++ return self.put('mds/set?var={0}&val={1}&confirm={2}' ++ .format(var, val, confirm), **kwargs) ++ else: ++ return self.put('mds/set?var={0}&val={1}' ++ .format(var, val), **kwargs) ++ ++ def mds_set_state(self, gid, state, **kwargs): ++ return self.put('mds/set_state?gid={0}&state={1}' ++ .format(gid, state), **kwargs) ++ + def mon_dump(self, epoch=None, **kwargs): + if epoch is not None: + return self.get('mon/dump?epoch={0}' +@@ -388,9 +418,6 @@ class CephWrapper(client.CephClient): + def mon_status(self, **kwargs): + return self.get('mon_status', **kwargs) + +- ### +- # mon PUT calls +- ### + def mon_add(self, name, addr, **kwargs): + return self.put('mon/add?name={0}&addr={1}' + .format(name, addr), **kwargs) +@@ -399,9 +426,38 @@ class CephWrapper(client.CephClient): + return self.put('mon/remove?name={0}' + .format(name), **kwargs) + +- ### +- # osd GET calls +- ### ++ def mon_compact(self, **kwargs): ++ return self.put('mon/compact', **kwargs) ++ ++ def mon_metadata(self, id, **kwargs): ++ return self.get('mon/metadata?id={0}' ++ .format(id), **kwargs) ++ ++ def mon_rm(self, name, **kwargs): ++ return self.put('mon/rm?name={0}' ++ .format(name), **kwargs) ++ ++ def mon_scrub(self, **kwargs): ++ return self.put('mon/scrub', **kwargs) ++ ++ def mon_sync_force(self, validate1=None, validate2=None, **kwargs): ++ request = [] ++ request.append('mon/sync/force') ++ if validate1 is not None: ++ request.append('validate1={0}'.format(validate1)) ++ if validate2 is not None: ++ request.append('validate2={0}'.format(validate2)) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) ++ ++ def node_ls(self, type=None, **kwargs): ++ if type is not None: ++ return self.get('node/ls?type={0}' ++ .format(type), **kwargs) ++ else: ++ return self.get('node/ls', **kwargs) ++ + def osd_blacklist_ls(self, **kwargs): + return self.get('osd/blacklist/ls', **kwargs) + +@@ -490,20 +546,26 @@ class CephWrapper(client.CephClient): + else: + return self.get('osd/lspools', **kwargs) + +- def osd_map(self, pool, object, **kwargs): +- return self.get('osd/map?pool={0}&object={1}' +- .format(pool, object), **kwargs) ++ def osd_map(self, pool, object, nspace=None, **kwargs): ++ if nspace is not None: ++ return self.get('osd/map?pool={0}&object={1}&nspace={2}' ++ .format(pool, object, nspace), **kwargs) ++ else: ++ return self.get('osd/map?pool={0}&object={1}' ++ .format(pool, object), **kwargs) + +- def osd_metadata(self, id, **kwargs): +- return self.get('osd/metadata?id={0}' +- .format(id), **kwargs) ++ def osd_metadata(self, id=None, **kwargs): ++ if id is not None: ++ return self.get('osd/metadata?id={0}' ++ .format(id), **kwargs) ++ else: ++ return self.get('osd/metadata', **kwargs) + + def osd_perf(self, **kwargs): + return self.get('osd/perf', **kwargs) + + def osd_get_pool_param(self, pool, var, **kwargs): +- return self.get('osd/pool/get?pool={0}&var={1}' +- .format(pool, var), **kwargs) ++ return self.osd_pool_get(pool, var, **kwargs) + + def osd_pool_get(self, pool, var, **kwargs): + return self.get('osd/pool/get?pool={0}&var={1}' +@@ -517,6 +579,9 @@ class CephWrapper(client.CephClient): + return self.get('osd/pool/stats', **kwargs) + + def osd_get_pool_quota(self, pool, **kwargs): ++ return self.osd_pool_get_quota(pool, **kwargs) ++ ++ def osd_pool_get_quota(self, pool, **kwargs): + return self.get('osd/pool/get-quota?pool={0}' + .format(pool), **kwargs) + +@@ -537,18 +602,28 @@ class CephWrapper(client.CephClient): + else: + return self.get('osd/tree', **kwargs) + +- ### +- # osd PUT calls +- ### +- def osd_blacklist(self, blacklistop, addr, expire, **kwargs): +- return self.put('osd/blacklist?blacklistop={0}&addr={1}&expire={2}' +- .format(blacklistop, addr, expire), **kwargs) +- +- def osd_create(self, uuid, **kwargs): +- return self.put('osd/create?uuid={0}' +- .format(uuid), **kwargs) ++ def osd_blacklist(self, blacklistop, addr, expire=None, **kwargs): ++ if expire is not None: ++ return self.put('osd/blacklist?blacklistop={0}&addr={1}&expire={2}' ++ .format(blacklistop, addr, expire), **kwargs) ++ else: ++ return self.put('osd/blacklist?blacklistop={0}&addr={1}' ++ .format(blacklistop, addr), **kwargs) ++ ++ def osd_create(self, uuid=None, id=None, **kwargs): ++ request = [] ++ request.append('osd/create') ++ if uuid is not None: ++ request.append('uuid={0}'.format(uuid)) ++ if id is not None: ++ request.append('id={0}'.format(id)) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) + + def osd_crush_add(self, id, weight, args, **kwargs): ++ if isinstance(args, list): ++ args = '&args='.join(args) + return self.put('osd/crush/add?id={0}&weight={1}&args={2}' + .format(id, weight, args), **kwargs) + +@@ -557,6 +632,8 @@ class CephWrapper(client.CephClient): + .format(name, type), **kwargs) + + def osd_crush_create_or_move(self, id, weight, args, **kwargs): ++ if isinstance(args, list): ++ args = '&args='.join(args) + return self.put('osd/crush/create-or-move?id={0}&weight={1}&args={2}' + .format(id, weight, args), **kwargs) + +@@ -565,10 +642,14 @@ class CephWrapper(client.CephClient): + .format(tunable), **kwargs) + + def osd_crush_link(self, name, args, **kwargs): +- return self.put('osd/crush/link?name={0}&args={2}' ++ if isinstance(args, list): ++ args = '&args='.join(args) ++ return self.put('osd/crush/link?name={0}&args={1}' + .format(name, args), **kwargs) + + def osd_crush_move(self, name, args, **kwargs): ++ if isinstance(args, list): ++ args = '&args='.join(args) + return self.put('osd/crush/move?name={0}&args={1}' + .format(name, args), **kwargs) + +@@ -595,7 +676,7 @@ class CephWrapper(client.CephClient): + return self.put('osd/crush/reweight-subtree?name={0}&weight={1}' + .format(name, weight), **kwargs) + +- def osd_crush_rm(self, name, ancestor, **kwargs): ++ def osd_crush_rm(self, name, ancestor=None, **kwargs): + if ancestor is not None: + return self.put('osd/crush/rm?name={0}&ancestor={1}' + .format(name, ancestor), **kwargs) +@@ -603,33 +684,35 @@ class CephWrapper(client.CephClient): + return self.put('osd/crush/rm?name={0}' + .format(name), **kwargs) + +- def osd_crush_rule_create_erasure(self, name, profile, **kwargs): +- return self.put( +- 'osd/crush/rule/create-erasure?name={0}&profile={1}' +- .format(name, profile), **kwargs) ++ def osd_crush_rule_create_erasure(self, name, profile=None, **kwargs): ++ if profile is not None: ++ return self.put('osd/crush/rule/create-erasure?name={0}&profile={1}' ++ .format(name, profile), **kwargs) ++ else: ++ return self.put('osd/crush/rule/create-erasure?name={0}' ++ .format(name), **kwargs) + +- def osd_crush_rule_create_simple(self, name, root, +- type, mode=None, **kwargs): ++ def osd_crush_rule_create_simple(self, name, root, type, mode=None, **kwargs): + if mode is not None: +- return self.put( +- 'osd/crush/rule/create-simple?name={0}&root={1}&type={2}' +- '&mode={3}'.format(name, root, type, mode), **kwargs) +- else: +- return self.put( +- 'osd/crush/rule/create-simple?name={0}&root={1}&type={2}' +- .format(name, root, type), **kwargs) ++ return self.put('osd/crush/rule/create-simple?name={0}&root={1}&type={2}&mode={3}' ++ .format(name, root, type, mode), **kwargs) ++ else: ++ return self.put('osd/crush/rule/create-simple?name={0}&root={1}&type={2}' ++ .format(name, root, type), **kwargs) + + def osd_crush_rule_rm(self, name, **kwargs): + return self.put('osd/crush/rule/rm?name={0}' + .format(name), **kwargs) + + def osd_crush_set(self, id, weight, args, **kwargs): ++ if isinstance(args, list): ++ args = '&args='.join(args) + return self.put('osd/crush/set?id={0}&weight={1}&args={2}' + .format(id, weight, args), **kwargs) + + def osd_crush_set_tunable(self, tunable, value, **kwargs): + return self.put('osd/crush/set-tunable?tunable={0}&value={1}' +- .format(tunable), **kwargs) ++ .format(tunable, value), **kwargs) + + def osd_crush_tunables(self, profile, **kwargs): + return self.put('osd/crush/tunables?profile={0}' +@@ -648,6 +731,8 @@ class CephWrapper(client.CephClient): + .format(who), **kwargs) + + def osd_down(self, ids, **kwargs): ++ if isinstance(ids, list): ++ ids = '&ids='.join(ids) + return self.put('osd/down?ids={0}' + .format(ids), **kwargs) + +@@ -664,6 +749,8 @@ class CephWrapper(client.CephClient): + .format(name), **kwargs) + + def osd_in(self, ids, **kwargs): ++ if isinstance(ids, list): ++ ids = '&ids='.join(ids) + return self.put('osd/in?ids={0}' + .format(ids), **kwargs) + +@@ -676,6 +763,8 @@ class CephWrapper(client.CephClient): + .format(id), **kwargs) + + def osd_out(self, ids, **kwargs): ++ if isinstance(ids, list): ++ ids = '&ids='.join(ids) + return self.put('osd/out?ids={0}' + .format(ids), **kwargs) + +@@ -690,32 +779,29 @@ class CephWrapper(client.CephClient): + return self.put('osd/pg-temp?pgid={0}' + .format(pgid), **kwargs) + +- def osd_pool_create(self, pool, pg_num, pgp_num, pool_type=None, +- erasure_code_profile=None, ruleset=None, +- expected_num_objects=None, **kwargs): ++ def osd_pool_create(self, pool, pg_num, pgp_num=None, pool_type=None, erasure_code_profile=None, ruleset=None, expected_num_objects=None, **kwargs): + request = [] +- request.append('osd/pool/create?pool={0}&pg_num={1}&pgp_num={2}' +- .format(pool, pg_num, pgp_num)) ++ request.append('osd/pool/create?pool={0}&pg_num={1}'.format(pool, pg_num)) ++ if pgp_num is not None: ++ request.append('pgp_num={0}'.format(pgp_num)) + if pool_type is not None: +- request.append('&pool_type={0}'.format(pool_type)) ++ request.append('pool_type={0}'.format(pool_type)) + if erasure_code_profile is not None: +- request.append('&erasure_code_profile={0}' +- .format(erasure_code_profile)) ++ request.append('erasure_code_profile={0}'.format(erasure_code_profile)) + if ruleset is not None: +- request.append('&ruleset={0}'.format(ruleset)) ++ request.append('ruleset={0}'.format(ruleset)) + if expected_num_objects is not None: +- request.append('&expected_num_objects={0}' +- .format(expected_num_objects)) +- return self.put(''.join(request), **kwargs) ++ request.append('expected_num_objects={0}'.format(expected_num_objects)) ++ return self.put('&'.join(request), **kwargs) + + def osd_pool_delete(self, pool, pool2=None, sure=None, **kwargs): + request = [] + request.append('osd/pool/delete?pool={0}'.format(pool)) + if pool2 is not None: +- request.append('&pool2={0}'.format(pool2)) ++ request.append('pool2={0}'.format(pool2)) + if sure is not None: +- request.append('&sure={0}'.format(sure)) +- return self.put(''.join(request), **kwargs) ++ request.append('sure={0}'.format(sure)) ++ return self.put('&'.join(request), **kwargs) + + def osd_pool_mksnap(self, pool, snap, **kwargs): + return self.put('osd/pool/mksnap?pool={0}&snap={1}' +@@ -730,12 +816,7 @@ class CephWrapper(client.CephClient): + .format(pool, snap), **kwargs) + + def osd_set_pool_param(self, pool, var, val, force=None, **kwargs): +- if force is not None: +- return self.put('osd/pool/set?pool={0}&var={1}&val={2}&force={3}' +- .format(pool, var, val, force), **kwargs) +- else: +- return self.put('osd/pool/set?pool={0}&var={1}&val={2}' +- .format(pool, var, val), **kwargs) ++ return self.osd_pool_set(pool, var, val, force, **kwargs) + + def osd_pool_set(self, pool, var, val, force=None, **kwargs): + if force is not None: +@@ -754,26 +835,57 @@ class CephWrapper(client.CephClient): + .format(pgid, id), **kwargs) + + def osd_set_pool_quota(self, pool, field, val, **kwargs): ++ return self.osd_pool_set_quota(pool, field, val, **kwargs) ++ ++ def osd_pool_set_quota(self, pool, field, val, **kwargs): + return self.put('osd/pool/set-quota?pool={0}&field={1}&val={2}' + .format(pool, field, val), **kwargs) + +- def osd_repair(self, pool, who, **kwargs): ++ ++ def osd_repair(self, who, **kwargs): + return self.put('osd/repair?who={0}' +- .format(pool, who), **kwargs) ++ .format(who), **kwargs) + + def osd_reweight(self, id, weight, **kwargs): + return self.put('osd/reweight?id={0}&weight={1}' + .format(id, weight), **kwargs) + +- def osd_reweight_by_pg(self, oload, pools, **kwargs): +- return self.put('osd/reweight-by-pg?oload={0}&pools={1}' +- .format(oload, pools), **kwargs) +- +- def osd_reweight_by_utilization(self, oload, **kwargs): +- return self.put('osd/reweight-by-utilization?oload={0}' +- .format(oload), **kwargs) ++ def osd_reweight_by_pg(self, oload=None, max_change=None, max_osds=None, pools=None, **kwargs): ++ request = [] ++ request.append('osd/reweight-by-pg') ++ if oload is not None: ++ request.append('oload={0}'.format(oload)) ++ if max_change is not None: ++ request.append('max_change={0}'.format(max_change)) ++ if max_osds is not None: ++ request.append('max_osds={0}'.format(max_osds)) ++ if pools is not None: ++ request.append('pools={0}'.format(pools)) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) ++ ++ def osd_reweight_by_utilization(self, oload=None, max_change=None, max_osds=None, no_increasing=None, **kwargs): ++ request = [] ++ request.append('osd/reweight-by-utilization') ++ if oload is not None: ++ request.append('oload={0}'.format(oload)) ++ if max_change is not None: ++ request.append('max_change={0}'.format(max_change)) ++ if max_osds is not None: ++ request.append('max_osds={0}'.format(max_osds)) ++ if no_increasing is not None: ++ request.append('no_increasing={0}'.format(no_increasing)) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) + + def osd_remove(self, ids, **kwargs): ++ return self.osd_rm(ids, **kwargs) ++ ++ def osd_rm(self, ids, **kwargs): ++ if isinstance(ids, list): ++ ids = '&ids='.join(ids) + return self.put('osd/rm?ids={0}' + .format(ids), **kwargs) + +@@ -782,14 +894,9 @@ class CephWrapper(client.CephClient): + .format(who), **kwargs) + + def osd_set_key(self, key, **kwargs): +- return self.put('osd/set?key={0}' +- .format(key), **kwargs) ++ return self.osd_set(key, **kwargs) + +- def osd_crushmap(self, **kwargs): +- """ +- osd/crushmap +- """ +- raise exceptions.FunctionNotImplemented() ++ # osd_crushmap() not defined in new api + + def osd_setmaxosd(self, newmax, **kwargs): + return self.put('osd/setmaxosd?newmax={0}' +@@ -801,21 +908,18 @@ class CephWrapper(client.CephClient): + + def osd_tier_add(self, pool, tierpool, force_nonempty=None, **kwargs): + if force_nonempty is not None: +- return self.put('osd/tier/add?pool={0}&tierpool={1}' +- '&force_nonempty={2}' ++ return self.put('osd/tier/add?pool={0}&tierpool={1}&force_nonempty={2}' + .format(pool, tierpool, force_nonempty), **kwargs) + else: + return self.put('osd/tier/add?pool={0}&tierpool={1}' + .format(pool, tierpool), **kwargs) + + def osd_tier_add_cache(self, pool, tierpool, size, **kwargs): +- return self.put('osd/tier/add-cache?pool={0}&tierpool={1}' +- '&size={2}' ++ return self.put('osd/tier/add-cache?pool={0}&tierpool={1}&size={2}' + .format(pool, tierpool, size), **kwargs) + + def osd_tier_cachemode(self, pool, mode, **kwargs): +- return self.put('osd/tier/cache-mode?pool={0}&mode={1}' +- .format(pool, mode), **kwargs) ++ return self.osd_tier_cache_mode(pool, mode, **kwargs) + + def osd_tier_remove(self, pool, tierpool, **kwargs): + return self.put('osd/tier/remove?pool={0}&tierpool={1}' +@@ -829,16 +933,81 @@ class CephWrapper(client.CephClient): + return self.put('osd/tier/set-overlay?pool={0}&overlaypool={1}' + .format(pool, overlaypool), **kwargs) + +- def osd_unpause(self, key, **kwargs): ++ def osd_unpause(self, **kwargs): + return self.put('osd/unpause', **kwargs) + + def osd_unset(self, key, **kwargs): + return self.put('osd/unset?key={0}' + .format(key), **kwargs) + +- ### +- # pg GET calls +- ### ++ def osd_blacklist_clear(self, **kwargs): ++ return self.put('osd/blacklist/clear', **kwargs) ++ ++ def osd_pool_rm(self, pool, pool2=None, sure=None, **kwargs): ++ request = [] ++ request.append('osd/pool/rm?pool={0}'.format(pool)) ++ if pool2 is not None: ++ request.append('pool2={0}'.format(pool2)) ++ if sure is not None: ++ request.append('sure={0}'.format(sure)) ++ return self.put('&'.join(request), **kwargs) ++ ++ def osd_set(self, key, **kwargs): ++ return self.put('osd/set?key={0}' ++ .format(key), **kwargs) ++ ++ def osd_setcrushmap(self, **kwargs): ++ return self.put('osd/setcrushmap', **kwargs) ++ ++ def osd_test_reweight_by_pg(self, oload=None, max_change=None, max_osds=None, pools=None, **kwargs): ++ request = [] ++ request.append('osd/test-reweight-by-pg') ++ if oload is not None: ++ request.append('oload={0}'.format(oload)) ++ if max_change is not None: ++ request.append('max_change={0}'.format(max_change)) ++ if max_osds is not None: ++ request.append('max_osds={0}'.format(max_osds)) ++ if pools is not None: ++ request.append('pools={0}'.format(pools)) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) ++ ++ def osd_test_reweight_by_utilization(self, oload=None, max_change=None, max_osds=None, no_increasing=None, **kwargs): ++ request = [] ++ request.append('osd/test-reweight-by-utilization') ++ if oload is not None: ++ request.append('oload={0}'.format(oload)) ++ if max_change is not None: ++ request.append('max_change={0}'.format(max_change)) ++ if max_osds is not None: ++ request.append('max_osds={0}'.format(max_osds)) ++ if no_increasing is not None: ++ request.append('no_increasing={0}'.format(no_increasing)) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) ++ ++ def osd_tier_cache_mode(self, pool, mode, sure=None, **kwargs): ++ if sure is not None: ++ return self.put('osd/tier/cache-mode?pool={0}&mode={1}&sure={2}' ++ .format(pool, mode, sure), **kwargs) ++ else: ++ return self.put('osd/tier/cache-mode?pool={0}&mode={1}' ++ .format(pool, mode), **kwargs) ++ ++ def osd_tier_rm(self, pool, tierpool, **kwargs): ++ return self.put('osd/tier/rm?pool={0}&tierpool={1}' ++ .format(pool, tierpool), **kwargs) ++ ++ def osd_tier_rm_overlay(self, pool, **kwargs): ++ return self.put('osd/tier/rm-overlay?pool={0}' ++ .format(pool), **kwargs) ++ ++ def osd_utilization(self, **kwargs): ++ return self.get('osd/utilization', **kwargs) ++ + def pg_debug(self, debugop, **kwargs): + kwargs['supported_body_types'] = ['text', 'xml'] + +@@ -866,15 +1035,12 @@ class CephWrapper(client.CephClient): + request = [] + request.append('pg/dump_stuck') + if stuckops is not None: +- request.append('?stuckops={0}'.format(stuckops)) ++ request.append('stuckops={0}'.format(stuckops)) + if threshold is not None: +- if stuckops is not None: +- request.append('&') +- else: +- request.append('?') + request.append('threshold={0}'.format(threshold)) +- +- return self.get(''.join(request), **kwargs) ++ if len(request) == 1: ++ return self.get(request[0], **kwargs) ++ return self.get(request[0] + '?' + '&'.join(request[1:]), **kwargs) + + def pg_getmap(self, **kwargs): + kwargs['supported_body_types'] = ['binary'] +@@ -885,21 +1051,21 @@ class CephWrapper(client.CephClient): + request = [] + request.append('pg/ls') + if pool is not None: +- request.append('?pool={0}'.format(pool)) ++ request.append('pool={0}'.format(pool)) + if states is not None: + request.append('states={0}'.format(states)) +- +- return self.get(''.join(request), **kwargs) ++ if len(request) == 1: ++ return self.get(request[0], **kwargs) ++ return self.get(request[0] + '?' + '&'.join(request[1:]), **kwargs) + + def pg_ls_by_osd(self, osd, pool=None, states=None, **kwargs): + request = [] + request.append('pg/ls-by-osd?osd={0}'.format(osd)) + if pool is not None: +- request.append('?pool={0}'.format(pool)) ++ request.append('pool={0}'.format(pool)) + if states is not None: + request.append('states={0}'.format(states)) +- +- return self.get(''.join(request), **kwargs) ++ return self.get('&'.join(request), **kwargs) + + def pg_ls_by_pool(self, poolstr, states=None, **kwargs): + if states is not None: +@@ -913,11 +1079,10 @@ class CephWrapper(client.CephClient): + request = [] + request.append('pg/ls-by-primary?osd={0}'.format(osd)) + if pool is not None: +- request.append('?pool={0}'.format(pool)) ++ request.append('pool={0}'.format(pool)) + if states is not None: + request.append('states={0}'.format(states)) +- +- return self.get(''.join(request), **kwargs) ++ return self.get('&'.join(request), **kwargs) + + def pg_map(self, pgid, **kwargs): + return self.get('pg/map?pgid={0}' +@@ -926,10 +1091,6 @@ class CephWrapper(client.CephClient): + def pg_stat(self, **kwargs): + return self.get('pg/stat', **kwargs) + +- ### +- # pg PUT calls +- ### +- + def pg_deep_scrub(self, pgid, **kwargs): + return self.put('pg/deep-scrub?pgid={0}' + .format(pgid), **kwargs) +@@ -957,20 +1118,20 @@ class CephWrapper(client.CephClient): + return self.put('pg/set_nearfull_ratio?ratio={0}' + .format(ratio), **kwargs) + +- ### +- # tell GET calls +- ### + def tell_debug_dump_missing(self, id, filename, **kwargs): +- return self.get('tell/{0}/debug_dump_missing?filename={1}' ++ return self.get('tell/{0}/debug/dump_missing?filename={1}' + .format(id, filename), **kwargs) + + def tell_dump_pg_recovery_stats(self, id, **kwargs): + return self.get('tell/{0}/dump_pg_recovery_stats' + .format(id), **kwargs) + +- def tell_list_missing(self, id, offset, **kwargs): +- return self.get('tell/{0}/list_missing?offset={1}' +- .format(id, offset), **kwargs) ++ def tell_list_missing(self, id, offset=None, **kwargs): ++ if offset is not None: ++ return self.get('tell/{0}/list_missing?offset={1}' ++ .format(id, offset), **kwargs) ++ else: ++ return self.get('tell/{0}/list_missing', **kwargs) + + def tell_query(self, id, **kwargs): + return self.get('tell/{0}/query' +@@ -979,3 +1140,55 @@ class CephWrapper(client.CephClient): + def tell_version(self, id, **kwargs): + return self.get('tell/{0}/version' + .format(id), **kwargs) ++ ++ def tell_bench(self, id, count=None, size=None, object_size=None, object_num=None, **kwargs): ++ request = [] ++ request.append('tell/{0}/bench'.format(id)) ++ if count is not None: ++ request.append('count={0}'.format(count)) ++ if size is not None: ++ request.append('size={0}'.format(size)) ++ if object_size is not None: ++ request.append('object_size={0}'.format(object_size)) ++ if object_num is not None: ++ request.append('object_num={0}'.format(object_num)) ++ if len(request) == 1: ++ return self.put(request[0], **kwargs) ++ return self.put(request[0] + '?' + '&'.join(request[1:]), **kwargs) ++ ++ def tell_cluster_log(self, id, level, message, **kwargs): ++ if isinstance(message, list): ++ message = '&message='.join(message) ++ return self.put('tell/{0}/cluster_log?level={1}&message={2}' ++ .format(id, level, message), **kwargs) ++ ++ def tell_cpu_profiler(self, id, arg, **kwargs): ++ return self.put('tell/{0}/cpu_profiler?arg={1}' ++ .format(id, arg), **kwargs) ++ ++ def tell_debug_kick_recovery_wq(self, id, delay, **kwargs): ++ return self.put('tell/{0}/debug/kick_recovery_wq?delay={1}' ++ .format(id, delay), **kwargs) ++ ++ def tell_flush_pg_stats(self, id, **kwargs): ++ return self.put('tell/{0}/flush_pg_stats' ++ .format(id), **kwargs) ++ ++ def tell_heap(self, id, heapcmd, **kwargs): ++ return self.put('tell/{0}/heap?heapcmd={1}' ++ .format(id, heapcmd), **kwargs) ++ ++ def tell_injectargs(self, id, injected_args, **kwargs): ++ if isinstance(injected_args, list): ++ injected_args = '&injected_args='.join(injected_args) ++ return self.put('tell/{0}/injectargs?injected_args={1}' ++ .format(id, injected_args), **kwargs) ++ ++ def tell_mark_unfound_lost(self, id, mulcmd, **kwargs): ++ return self.put('tell/{0}/mark_unfound_lost?mulcmd={1}' ++ .format(id, mulcmd), **kwargs) ++ ++ def tell_reset_pg_recovery_stats(self, id, **kwargs): ++ return self.put('tell/{0}/reset_pg_recovery_stats' ++ .format(id), **kwargs) ++ diff --git a/ceph/python-cephclient/python-cephclient/add-osd-get-pool-quota.patch b/ceph/python-cephclient/python-cephclient/add-osd-get-pool-quota.patch new file mode 100644 index 00000000..4127d7eb --- /dev/null +++ b/ceph/python-cephclient/python-cephclient/add-osd-get-pool-quota.patch @@ -0,0 +1,15 @@ +Index: git/cephclient/wrapper.py +=================================================================== +--- git.orig/cephclient/wrapper.py 2015-10-26 16:00:32.768154102 +0200 ++++ git/cephclient/wrapper.py 2015-11-04 14:46:09.491855340 +0200 +@@ -412,6 +412,10 @@ + else: + return self.get('osd/pool/stats', **kwargs) + ++ def osd_get_pool_quota(self, pool, **kwargs): ++ return self.get('osd/pool/get-quota?pool={0}' ++ .format(pool), **kwargs) ++ + def osd_stat(self, **kwargs): + return self.get('osd/stat', **kwargs) + diff --git a/ceph/python-cephclient/python-cephclient/fix-osd-crush-remove.patch b/ceph/python-cephclient/python-cephclient/fix-osd-crush-remove.patch new file mode 100644 index 00000000..2f611a75 --- /dev/null +++ b/ceph/python-cephclient/python-cephclient/fix-osd-crush-remove.patch @@ -0,0 +1,25 @@ +--- + cephclient/wrapper.py | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +Index: git/cephclient/wrapper.py +=================================================================== +--- git.orig/cephclient/wrapper.py ++++ git/cephclient/wrapper.py +@@ -449,9 +449,13 @@ class CephWrapper(client.CephClient): + return self.put('osd/crush/move?name={0}&args={1}' + .format(name, args), **kwargs) + +- def osd_crush_remove(self, name, ancestor, **kwargs): +- return self.put('osd/crush/remove?name={0}&ancestor={1}' +- .format(name, ancestor), **kwargs) ++ def osd_crush_remove(self, name, ancestor=None, **kwargs): ++ if ancestor: ++ return self.put('osd/crush/remove?name={0}&ancestor={1}' ++ .format(name, ancestor), **kwargs) ++ else: ++ return self.put('osd/crush/remove?name={0}' ++ .format(name), **kwargs) + + def osd_crush_reweight(self, name, weight, **kwargs): + return self.put('osd/crush/reweight?name={0}&weight={1}' diff --git a/ceph/python-cephclient/python-cephclient/fix-osd-tier-add.patch b/ceph/python-cephclient/python-cephclient/fix-osd-tier-add.patch new file mode 100644 index 00000000..c07f5319 --- /dev/null +++ b/ceph/python-cephclient/python-cephclient/fix-osd-tier-add.patch @@ -0,0 +1,19 @@ +diff -rupN a/cephclient/wrapper.py b/cephclient/wrapper.py +--- a/cephclient/wrapper.py 2016-07-04 21:59:06.000000000 +0300 ++++ b/cephclient/wrapper.py 2016-07-07 18:01:50.000000000 +0300 +@@ -799,11 +799,11 @@ class CephWrapper(client.CephClient): + return self.put('osd/thrash?num_epochs={0}' + .format(num_epochs), **kwargs) + +- def osd_tier_add(self, pool, tierpool, force_notempty=None, **kwargs): +- if force_notempty is not None: ++ def osd_tier_add(self, pool, tierpool, force_nonempty=None, **kwargs): ++ if force_nonempty is not None: + return self.put('osd/tier/add?pool={0}&tierpool={1}' +- '&force_notempty={2}' +- .format(pool, tierpool, force_notempty), **kwargs) ++ '&force_nonempty={2}' ++ .format(pool, tierpool, force_nonempty), **kwargs) + else: + return self.put('osd/tier/add?pool={0}&tierpool={1}' + .format(pool, tierpool), **kwargs) diff --git a/ceph/python-cephclient/python-cephclient/set-default-endpoint.patch b/ceph/python-cephclient/python-cephclient/set-default-endpoint.patch new file mode 100644 index 00000000..40adee89 --- /dev/null +++ b/ceph/python-cephclient/python-cephclient/set-default-endpoint.patch @@ -0,0 +1,20 @@ +--- + cephclient/client.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/cephclient/client.py ++++ b/cephclient/client.py +@@ -53,7 +53,12 @@ class CephClient(object): + + self.log.debug("Params: {0}".format(str(self.params))) + +- self.endpoint = self.params['endpoint'] ++ if 'endpoint' in self.params: ++ self.endpoint = self.params['endpoint'] ++ else: ++ # default endpoint ++ self.endpoint = 'http://localhost:5001/api/v0.1/' ++ + if 'timeout' not in self.params: + self.timeout = None + diff --git a/utilities/namespace-utils/LICENSE b/utilities/namespace-utils/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/utilities/namespace-utils/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/utilities/namespace-utils/centos/build_srpm.data b/utilities/namespace-utils/centos/build_srpm.data new file mode 100644 index 00000000..e981e8b5 --- /dev/null +++ b/utilities/namespace-utils/centos/build_srpm.data @@ -0,0 +1,2 @@ +SRC_DIR="namespace-utils" +TIS_PATCH_VER=0 diff --git a/utilities/namespace-utils/centos/namespace-utils.spec b/utilities/namespace-utils/centos/namespace-utils.spec new file mode 100644 index 00000000..601b11ec --- /dev/null +++ b/utilities/namespace-utils/centos/namespace-utils.spec @@ -0,0 +1,35 @@ +%define _CC gcc + +Summary: namespace utils +Name: namespace-utils +Version: 1.0 +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz + +%description +Titanium Cloud namespace utilities + +%prep +%setup -q + +%build +%{_CC} -o bashns bashns.c + +%install +rm -rf ${RPM_BUILD_ROOT} +install -d -m 755 ${RPM_BUILD_ROOT}%{_sbindir} +install -m 500 bashns ${RPM_BUILD_ROOT}%{_sbindir} +install -m 500 umount-in-namespace ${RPM_BUILD_ROOT}%{_sbindir} + +%clean +rm -rf ${RPM_BUILD_ROOT} + +%files +%license LICENSE +%defattr(-,root,root,-) +%{_sbindir}/umount-in-namespace +%{_sbindir}/bashns diff --git a/utilities/namespace-utils/namespace-utils/LICENSE b/utilities/namespace-utils/namespace-utils/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/utilities/namespace-utils/namespace-utils/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/utilities/namespace-utils/namespace-utils/bashns.c b/utilities/namespace-utils/namespace-utils/bashns.c new file mode 100644 index 00000000..2a9c15e5 --- /dev/null +++ b/utilities/namespace-utils/namespace-utils/bashns.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015 Wind River Systems, Inc. +* +* SPDX-License-Identifier: Apache-2.0 +* + */ + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include + +void usage(char *name) +{ + printf("usage: %s \n", name); + +} + +int main(int argc, char **argv) { + if (argc < 2) { + printf("usage: %s \n", argv[0]); + return -1; + } + + int pid = atoi(argv[1]); + printf("trying to open filesystem namespace of pid %d\n", pid); + + char buf[100]; + sprintf(buf, "/proc/%d/ns/mnt", pid); + + printf("trying to open %s\n", buf); + + int fd = open(buf, O_RDWR); + if (fd < 1) { + perror("unable to open file"); + return -1; + } + + printf("got fd, trying to set namespace\n"); + + int rc = setns(fd, 0); + if (rc < 0) { + perror("unable to set namespace"); + return -1; + } + + printf("entered namespace successfully, trying to exec bash\n"); + + rc = execvp("bash", 0); + if (rc < 0) { + perror("unable to exec bash"); + return -1; + } +} + diff --git a/utilities/namespace-utils/namespace-utils/umount-in-namespace b/utilities/namespace-utils/namespace-utils/umount-in-namespace new file mode 100644 index 00000000..934daeae --- /dev/null +++ b/utilities/namespace-utils/namespace-utils/umount-in-namespace @@ -0,0 +1,25 @@ +#!/bin/bash + +# +# Copyright (c) 2015 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +MNT=$1 + +SELF_NS=$(ls -l /proc/self/ns/mnt 2>/dev/null| sed -r 's/.*\[(.*)\]/\1/') + +ls -l /proc/*/ns/mnt 2>/dev/null| sed -r 's/.*\[(.*)\]/\1/' | sort -u | while read ns +do + if [ "$ns" = "$SELF_NS" ] + then + continue + fi + + ls -l /proc/*/ns/mnt 2>/dev/null | grep $ns |grep '/proc/[0-9]*/' | sed -r 's#.*/proc/([0-9]*)/ns.*#\1#' | while read pid + do + echo "umount -n -l $MNT" | /usr/sbin/bashns $pid + done +done + diff --git a/utilities/nfscheck/LICENSE b/utilities/nfscheck/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/utilities/nfscheck/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/utilities/nfscheck/PKG-INFO b/utilities/nfscheck/PKG-INFO new file mode 100644 index 00000000..0800a114 --- /dev/null +++ b/utilities/nfscheck/PKG-INFO @@ -0,0 +1,14 @@ +Metadata-Version: 1.1 +Name: nfscheck +Version: 1.0 +Summary: NFS Audit +Home-page: +Author: +Author-email: +License: Apache-2.0 + +Description: +NFS Audit + + +Platform: UNKNOWN diff --git a/utilities/nfscheck/centos/build_srpm.data b/utilities/nfscheck/centos/build_srpm.data new file mode 100644 index 00000000..4498c84d --- /dev/null +++ b/utilities/nfscheck/centos/build_srpm.data @@ -0,0 +1,2 @@ +COPY_LIST="LICENSE files/*" +TIS_PATCH_VER=0 diff --git a/utilities/nfscheck/centos/nfscheck.spec b/utilities/nfscheck/centos/nfscheck.spec new file mode 100644 index 00000000..4ba09bd0 --- /dev/null +++ b/utilities/nfscheck/centos/nfscheck.spec @@ -0,0 +1,43 @@ +Name: nfscheck +Version: 1.0 +Release: %{tis_patch_ver}%{?_tis_dist} +Summary: NFS Audit + +Group: base +License: Apache-2.0 +URL: unknown +Source0: nfscheck.sh +Source1: nfscheck.service +Source2: LICENSE + +Requires: systemd +Requires: util-linux + +%description +NFS Audit + + +%prep + + +%build + + +%install +install -d -m 755 %{buildroot}/usr/bin/ +install -m 755 %{SOURCE0} %{buildroot}/usr/bin/nfscheck.sh + +install -d -m 755 %{buildroot}/usr/lib/systemd/system/ +install -m 664 %{SOURCE1} %{buildroot}/usr/lib/systemd/system/nfscheck.service + +%post +/usr/bin/systemctl enable nfscheck.service >/dev/null 2>&1 + +%files +%license ../SOURCES/LICENSE +/usr/bin/* +/usr/lib/systemd/system/* + + +%changelog + diff --git a/utilities/nfscheck/files/LICENSE b/utilities/nfscheck/files/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/utilities/nfscheck/files/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/utilities/nfscheck/files/nfscheck-init.sh b/utilities/nfscheck/files/nfscheck-init.sh new file mode 100755 index 00000000..ac2d8692 --- /dev/null +++ b/utilities/nfscheck/files/nfscheck-init.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +# chkconfig: 345 99 10 + +### BEGIN INIT INFO +# Provides: nfscheck +# Required-Start: $syslog +# Required-Stop: $syslog +# Default-Start: 2 3 5 +# Default-Stop: 0 1 6 +# Short-Description: nfscheck +# Description: NFS Audit +### END INIT INFO + +DESC="nfscheck" +DAEMON="/usr/bin/nfscheck" +PIDFILE="/var/run/nfscheck.pid" + +start() +{ + if [ -e $PIDFILE ]; then + PIDDIR=/proc/$(cat $PIDFILE) + if [ -d ${PIDDIR} ]; then + echo "$DESC already running." + exit 1 + else + echo "Removing stale PID file $PIDFILE" + rm -f $PIDFILE + fi + fi + + echo -n "Starting $DESC..." + + start-stop-daemon --start --quiet --background \ + --pidfile ${PIDFILE} --make-pidfile --exec ${DAEMON} + + if [ $? -eq 0 ]; then + echo "done." + else + echo "failed." + fi +} + +stop() +{ + echo -n "Stopping $DESC..." + start-stop-daemon --stop --quiet --pidfile $PIDFILE + if [ $? -eq 0 ]; then + echo "done." + else + echo "failed." + fi + rm -f $PIDFILE +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart|force-reload) + stop + start + ;; + *) + echo "Usage: $0 {start|stop|force-reload|restart}" + exit 1 + ;; +esac + +exit 0 diff --git a/utilities/nfscheck/files/nfscheck.service b/utilities/nfscheck/files/nfscheck.service new file mode 100644 index 00000000..e83300e8 --- /dev/null +++ b/utilities/nfscheck/files/nfscheck.service @@ -0,0 +1,10 @@ +[Unit] +Description=nfscheck +After=syslog.target network.target nfs-mountd.service sw-patch.service + +[Service] +Type=simple +ExecStart=/bin/sh /usr/bin/nfscheck.sh + +[Install] +WantedBy=multi-user.target diff --git a/utilities/nfscheck/files/nfscheck.sh b/utilities/nfscheck/files/nfscheck.sh new file mode 100644 index 00000000..f58ab80e --- /dev/null +++ b/utilities/nfscheck/files/nfscheck.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +# The following script tests the NFS mount in order to log when it is hung + +MOUNT=/opt/platform +previous=1 +delay=60 + +while : +do + # First, check that it's actually an NFS mount + mount | grep -q $MOUNT + if [ $? -ne 0 ] + then + logger -t NFSCHECK "$MOUNT is not mounted" + previous=1 + sleep $delay + continue + fi + + ls $MOUNT >/dev/null 2>&1 & + + sleep $delay + + # At this point, jobs will either report no jobs (empty) or Done, + # unless the job is still running/hung + rc=$(jobs) + if [[ -z "$rc" || $rc =~ "Done" ]] + then + # NFS is successful + if [ $previous -ne 0 ] + then + logger -t NFSCHECK "NFS test of $MOUNT is ok" + previous=0 + fi + else + # Keep waiting until the job is done + while ! [[ -z "$rc" || $rc =~ "Done" ]] + do + logger -t NFSCHECK "NFS test of $MOUNT is failed" + previous=1 + sleep $delay + rc=$(jobs) + done + fi +done + diff --git a/utilities/stx-extensions/PKG-INFO b/utilities/stx-extensions/PKG-INFO new file mode 100644 index 00000000..80d6c515 --- /dev/null +++ b/utilities/stx-extensions/PKG-INFO @@ -0,0 +1,13 @@ +Metadata-Version: 1.1 +Name: tis-extensions +Version: 1.0 +Summary: TIS Extensions to thirdparty pkgs +Home-page: +Author: Windriver +Author-email: info@windriver.com +License: Apache-2.0 + +Description: TIS Extensions to thirdparty pkgs + + +Platform: UNKNOWN diff --git a/utilities/stx-extensions/centos/build_srpm.data b/utilities/stx-extensions/centos/build_srpm.data new file mode 100644 index 00000000..75f295c2 --- /dev/null +++ b/utilities/stx-extensions/centos/build_srpm.data @@ -0,0 +1,2 @@ +SRC_DIR="files" +TIS_PATCH_VER=2 diff --git a/utilities/stx-extensions/centos/tis-extensions.spec b/utilities/stx-extensions/centos/tis-extensions.spec new file mode 100644 index 00000000..179b7724 --- /dev/null +++ b/utilities/stx-extensions/centos/tis-extensions.spec @@ -0,0 +1,69 @@ +# +# The tis-extensions group of packages is intended to allow us to +# add files to "extend" thirdparty packages, such as by packaging +# custom systemd files into /etc/systemd to override the originals +# without modifying or rebuilding the thirdparty package. +# + +Name: tis-extensions +Version: 1.0 +Summary: TIS Extensions to thirdparty pkgs +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz + +%define debug_package %{nil} + +Requires: systemd + +%description +TIS Extensions to thirdparty pkgs + +%package -n %{name}-controller +Summary: TIS Extensions to thirdparty pkg on controller +Group: base + +%description -n %{name}-controller +TIS Extensions to thirdparty pkgs on controller + +%define local_etc_systemd %{_sysconfdir}/systemd/system/ +%define local_etc_coredump %{_sysconfdir}/systemd/coredump.conf.d +%define local_etc_initd %{_sysconfdir}/init.d +%define local_etc_sysctl %{_sysconfdir}/sysctl.d +%define local_etc_modload %{_sysconfdir}/modules-load.d + +%prep +%setup + +%build + +%install +install -d -m 755 %{buildroot}%{local_etc_initd} +install -p -D -m 555 target %{buildroot}%{local_etc_initd}/target + +install -d -m 755 %{buildroot}%{local_etc_systemd} +install -p -D -m 444 target.service %{buildroot}%{local_etc_systemd}/target.service + +install -d -m 755 %{buildroot}%{local_etc_sysctl} +install -p -D -m 644 coredump-sysctl.conf %{buildroot}%{local_etc_sysctl}/50-coredump.conf + +install -d -m 755 %{buildroot}%{local_etc_coredump} +install -p -D -m 644 coredump.conf %{buildroot}%{local_etc_coredump}/coredump.conf + +install -d -m 755 %{buildroot}%{local_etc_modload} +install -p -D -m 644 modules-load-vfio.conf %{buildroot}%{local_etc_modload}/vfio.conf + +%files +%defattr(-,root,root,-) +%{local_etc_sysctl}/50-coredump.conf +%{local_etc_coredump}/coredump.conf +%{local_etc_modload}/vfio.conf +%doc LICENSE + +%files -n %{name}-controller +%defattr(-,root,root,-) +%{local_etc_initd}/target +%{local_etc_systemd}/target.service diff --git a/utilities/stx-extensions/files/LICENSE b/utilities/stx-extensions/files/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/utilities/stx-extensions/files/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/utilities/stx-extensions/files/coredump-sysctl.conf b/utilities/stx-extensions/files/coredump-sysctl.conf new file mode 100644 index 00000000..5a776f7a --- /dev/null +++ b/utilities/stx-extensions/files/coredump-sysctl.conf @@ -0,0 +1,4 @@ +# send coredumps to the systemd coredump utility. +kernel.core_pattern=|/usr/lib/systemd/systemd-coredump %p %u %g %s %t %e +kernel.core_pipe_limit = 4 +kernel.core_uses_pid = 1 diff --git a/utilities/stx-extensions/files/coredump.conf b/utilities/stx-extensions/files/coredump.conf new file mode 100644 index 00000000..3b966b28 --- /dev/null +++ b/utilities/stx-extensions/files/coredump.conf @@ -0,0 +1,8 @@ +[Coredump] +Storage=external +Compress=yes +#ProcessSizeMax=2G +#ExternalSizeMax=2G +#JournalSizeMax=767M +#MaxUse= +#KeepFree= diff --git a/utilities/stx-extensions/files/modules-load-vfio.conf b/utilities/stx-extensions/files/modules-load-vfio.conf new file mode 100644 index 00000000..7a497c56 --- /dev/null +++ b/utilities/stx-extensions/files/modules-load-vfio.conf @@ -0,0 +1 @@ +vfio diff --git a/utilities/stx-extensions/files/target b/utilities/stx-extensions/files/target new file mode 100644 index 00000000..259fa012 --- /dev/null +++ b/utilities/stx-extensions/files/target @@ -0,0 +1,290 @@ +#!/bin/bash +# +# Filename: /etc/init.d/target +# +# Bring up/down iscsi LIO target +# +######################################################################### +# + +# +# Copyright (c) 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +DESC="target" +STATUS_FILE="/var/run/lio-target.running" + +CINDER_CONF_DIR="/opt/cgcs/cinder" +LIO_CONF_DIR="${CINDER_CONF_DIR}/iscsi-target" +LIO_CONF_FILE="${LIO_CONF_DIR}/saveconfig.json" +TGT_CONF_FILE="${CINDER_CONF_DIR}/data/tgt-initiators-15.12-upgrade.conf" +BASE_TARGET_DIR="/etc/target" + +# Tools +TARGETCLI="/usr/bin/targetcli" +RTSTOOL="/usr/bin/cinder-rtstool" +SM_QUERY="/usr/bin/sm-query" + +# This will log to /var/log/platform.log + +NAME=$(basename $0) + +function log () { + logger -p local1.info "${NAME}: $1" +} + +# Determine whether we are running on the active controller. +# Return value: 0 - controller is active, 1 - not active. + +is_active_controller () { + + # service drbd-cgcs - should be active before iscsi one + local SERVICE="drbd-cgcs" + local ACTIVE=$(${SM_QUERY} service ${SERVICE} | \ + grep enabled-active) + + if [ -z "${ACTIVE}" ] ; then + return 1 + else + return 0 + fi +} + + +# This is a function that migrates 15.12 TGT Target configuration +# to the LIO Target configuration file. The function is called only +# once on the first "swact" to the LIO controller after +# Software Upgrade. + +migrate_tgt () { + + log "Migrating 15.12 TGT iSCSI Target to LIO" + + # TGT configuration directory + TGT_CONF_DIR="/opt/cgcs/cinder/data/volumes" + + # Start the LIO target and enable it for configuration + /usr/bin/targetctl restore + + if [ $? -ne 0 ] ; then + log "ERROR: trying to start the LIO target" + return 1 + fi + + if [ ! -d ${TGT_CONF_DIR} ] ; then + # User does not have attached volumes + log "No volumes to migrate. Migration is done" + return 0 + fi + + if [ ! "$(ls -A ${TGT_CONF_DIR})" ] ; then + # Cinder volumes configuration is empty + log "No volumes to migrate. Migration is done" + return 0 + fi + + PORTAL_IP="" + + if [ -e /etc/hosts ] ; then + PORTAL_IP=$(grep controller-cinder /etc/hosts | awk '{print $1}') + fi + + # If no Portal IP is specified, use default IP address + if [ -z "${PORTAL_IP}" ] ; then + PORTAL_IP="0.0.0.0" + fi + + for volume in `find ${TGT_CONF_DIR} -name "volume-*"` + do + TARGET_NAME=$(grep -n target ${volume} | awk '{ print $2}' | \ + sed 's/>//') + DEVICE=$(grep -n backing-store ${volume} | awk '{print $3}') + + USERID=$(grep -n incominguser ${volume} | awk '{print $3}') + + PASSWORD=$(grep -n incominguser ${volume} | awk '{print $4}') + + INITIATOR=$(grep -n ${TARGET_NAME} ${TGT_CONF_FILE} | \ + awk '{ print $5 }') + + if [ ! "${TARGET_NAME}" -a "${DEVICE}" -a "${USERID}" -a \ + "${PASSWORD}" -a "${INITIATOR}" ] ; then + log "ERROR: volume ${TARGET_NAME} configuration is not complete" + continue + fi + # Add the volume to the LIO configuration + ${RTSTOOL} create ${DEVICE} ${TARGET_NAME} ${USERID} ${PASSWORD} \ + False -a${PORTAL_IP} -p3260 2>/dev/null + + if [ $? -ne 0 ] ; then + log "ERROR: Target creation failed for volume ${TARGET_NAME}" + continue + fi + + log "Created target ${TARGET_NAME}" + + ${RTSTOOL} add-initiator ${TARGET_NAME} ${USERID} ${PASSWORD} \ + ${INITIATOR} 2>/dev/null + + if [ $? -ne 0 ] ; then + log "ERROR: Add Initiator ${INITIATOR} failed for ${TARGET_NAME}" + continue + fi + log "Added Initiator ${INITIATOR} for ${TARGET_NAME}" + + # Create a lun mapping from 1 to 0. Why? Well 15.12 used tgt which + # uses lun 1 as the first volume, but lio uses lun 0. This mapping + # allows iscsi references created in the old tgt realm to continue + # to work. + ${TARGETCLI} "/iscsi/${TARGET_NAME}/tpg1/acls/${INITIATOR} create 1 0" + if [ $? -ne 0 ] ; then + log "ERROR: lun 1 mapping failed: Initiator ${INITIATOR} Target ${TARGET_NAME}" + else + log "Added lun 1 mapping: Initiator ${INITIATOR} Target ${TARGET_NAME}" + fi + done + + # Save and verify the new LIO configuration + ${RTSTOOL} save 2> /dev/null + + if [ $? -ne 0 ] ; then + log "ERROR: Cannot save LIO Target configuration" + return 1 + fi + + ${RTSTOOL} verify 2> /dev/null + + if [ $? -ne 0 ] ; then + log "ERROR: LIO Target verification failed" + return 1 + fi + + log "TGT to LIO migration is done" + return 0 +} + +start () { + + echo -n "Starting ${DESC}..." + + if ! is_active_controller ; then + echo "failed. Controller is not active." + exit 1 + fi + + if [ ! -L ${BASE_TARGET_DIR} ] ; then + rm -rf ${BASE_TARGET_DIR} + ln -s ${LIO_CONF_DIR} ${BASE_TARGET_DIR} + fi + + if [ ! -d ${LIO_CONF_DIR} ] ; then + # Create LIO configuration directory + mkdir -p ${LIO_CONF_DIR} && log "Created ${LIO_CONF_DIR}" + + # Create default LIO configuration file + ${TARGETCLI} saveconfig ${LIO_CONF_FILE} + fi + + if [ -e ${TGT_CONF_FILE} -a -s ${TGT_CONF_FILE} ] ; then + migrate_tgt + + if [ $? -ne 0 ] ; then + echo "tgt migration failed." + exit 1 + fi + mv -f ${TGT_CONF_FILE} ${TGT_CONF_FILE}.bak + else + + /usr/bin/targetctl restore + + if [ $? -ne 0 ] ; then + echo "failed." + exit 1 + fi + fi + + touch ${STATUS_FILE} + + echo "done." +} + +stop () { + + echo -n "Stopping ${DESC}..." + + if [ ! -f ${STATUS_FILE} ] ; then + echo "service has not been started" + exit 0 + fi + + /usr/bin/targetctl clear + + RET=$? + + if [ -f ${STATUS_FILE} ] ; then + rm -f ${STATUS_FILE} + fi + + if [ ${RET} -ne 0 ] ; then + echo "failed." + exit 1 + fi + + echo -n +} + +status() +{ + if [ ! -f ${STATUS_FILE} ] ; then + echo "${DESC} has not been started" + exit 3 + else + echo "${DESC} had been started" + fi +} + +restart () { + stop + start +} + +reload() +{ + if [ ! -f ${STATUS_FILE} ] ; then + echo "${DESC} has not been started" + exit 1 + fi + + /usr/bin/targetctl restore + + if [ $? -ne 0 ] ; then + echo "failed." + exit 1 + fi +} + +case "$1" in + start) + start + ;; + status) + status + ;; + stop|forcedstop) + stop + ;; + reload|force-reload) + reload + ;; + restart|try-restart) + restart + ;; + *) + echo $"Usage: $0 {start|status|stop|forcedstop|restart|try-restart|reload|force-reload}" + exit 1 + ;; +esac + +exit 0 diff --git a/utilities/stx-extensions/files/target.service b/utilities/stx-extensions/files/target.service new file mode 100644 index 00000000..7311e0c2 --- /dev/null +++ b/utilities/stx-extensions/files/target.service @@ -0,0 +1,14 @@ +[Unit] +Description=iscsi LIO target service +After=config.service + +[Service] +Type=oneshot +ExecStart=/etc/init.d/target +ExecStop= +ExecReload= +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/utilities/update-motd/LICENSE b/utilities/update-motd/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/utilities/update-motd/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/utilities/update-motd/PKG-INFO b/utilities/update-motd/PKG-INFO new file mode 100644 index 00000000..b11affb6 --- /dev/null +++ b/utilities/update-motd/PKG-INFO @@ -0,0 +1,14 @@ +Metadata-Version: 1.1 +Name: update-motd +Version: 1.0 +Summary: dynamic MOTD generation +Home-page: +Author: +Author-email: +License: Apache-2.0 + +Description: +dynamic MOTD generation + + +Platform: UNKNOWN diff --git a/utilities/update-motd/centos/build_srpm.data b/utilities/update-motd/centos/build_srpm.data new file mode 100644 index 00000000..2ec7ea02 --- /dev/null +++ b/utilities/update-motd/centos/build_srpm.data @@ -0,0 +1,2 @@ +COPY_LIST="files/*" +TIS_PATCH_VER=1 diff --git a/utilities/update-motd/centos/update-motd.spec b/utilities/update-motd/centos/update-motd.spec new file mode 100644 index 00000000..321547e2 --- /dev/null +++ b/utilities/update-motd/centos/update-motd.spec @@ -0,0 +1,59 @@ +Name: update-motd +Version: 1.0 +Release: %{tis_patch_ver}%{?_tis_dist} +Summary: dynamic MOTD generation + +Group: base +License: Apache-2.0 +URL: unknown +Source0: motd-footer +Source1: motd-header +Source2: motd-update +Source3: motd-update.cron +Source4: customize-banner +Source5: apply_banner_customization +Source6: install_banner_customization +Source7: LICENSE + +Requires: crontabs + +%description +dynamic MOTD generation + +%prep + + +%build + + +%install +install -d %{buildroot}%{_sbindir} +install -m 700 %{SOURCE2} %{buildroot}%{_sbindir}/motd-update + +install -d %{buildroot}%{_sysconfdir} + +install -d %{buildroot}%{_sysconfdir}/motd.d +install -m 755 %{SOURCE1} %{buildroot}%{_sysconfdir}/motd.d/00-header +install -m 755 %{SOURCE0} %{buildroot}%{_sysconfdir}/motd.d/99-footer + +install -d %{buildroot}%{_sysconfdir}/cron.d +install -m 600 %{SOURCE3} %{buildroot}%{_sysconfdir}/cron.d/motd-update +install -m 700 %{SOURCE4} %{buildroot}%{_sbindir}/customize-banner +install -m 700 %{SOURCE5} %{buildroot}%{_sbindir}/apply_banner_customization +install -m 700 %{SOURCE6} %{buildroot}%{_sbindir}/install_banner_customization + + +%files +%license ../SOURCES/LICENSE +%dir %{_sysconfdir}/motd.d/ +%{_sysconfdir}/motd.d/* +/usr/sbin/* +/etc/motd.d/* +/etc/cron.d/* +%{_sbindir}/motd-update +%{_sbindir}/customize-banner +%{_sbindir}/apply_banner_customization +%{_sbindir}/install_banner_customization + +%changelog + diff --git a/utilities/update-motd/files/LICENSE b/utilities/update-motd/files/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/utilities/update-motd/files/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/utilities/update-motd/files/apply_banner_customization b/utilities/update-motd/files/apply_banner_customization new file mode 100644 index 00000000..3bf999e7 --- /dev/null +++ b/utilities/update-motd/files/apply_banner_customization @@ -0,0 +1,25 @@ +#!/bin/bash + +# +# Copyright (c) 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +. /usr/sbin/customize-banner + +banner_path="$1" +if [ -z "${banner_path}" ]; then + banner_path=$(pwd) +fi + +if ! customize_banner "${banner_path}"; then + exit 1 +fi + +install_banner_files + +# recreate /etc/motd +/usr/sbin/motd-update + +exit 0 diff --git a/utilities/update-motd/files/customize-banner b/utilities/update-motd/files/customize-banner new file mode 100644 index 00000000..0d798fba --- /dev/null +++ b/utilities/update-motd/files/customize-banner @@ -0,0 +1,286 @@ +#!/bin/bash + +# +# Copyright (c) 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +. /usr/bin/tsconfig + +OPT_BANNER_BACKUP="/opt/banner.bk" +PLATFORM_BANNER_DIR="${CONFIG_PATH}/banner" + +# +# set BANNER_VERBOSE to enable info logs +# +export BANNER_VERBOSE + +info_log () +{ + if [ -n "${BANNER_VERBOSE}" ]; then + echo "INFO: customize-banner: $@" >&2 + fi +} + +warn_log () +{ + echo "WARNING: customize-banner: $@" >&2 +} + +error_log () +{ + echo "ERROR: customize-banner: $@" >&2 +} + +# some checks to see if the user does something odd +# Return: 1 if the file is not sane +# 0 if the file is normal looking +# +# Symbolic links are followed to their ultimate destination before +# further checks are made +file_is_sane () +{ + local fname=$1 + + if [ -z "${fname}" ]; then + error_log "no file specified" + return 1 + fi + + # resolve symlinks + if [ -h "${fname}" ]; then + local resolved=$(readlink -f "${fname}") + if [ -z "${resolved}" ]; then + error_log "file does not exist; did not resolve symbolic link" + return 1 + fi + + file_is_sane_no_link "${resolved}" + return $? + fi + + file_is_sane_no_link "${fname}" + return $? +} + +file_is_sane_no_link () +{ + local fname=$1 + # a sanity check, the banner file has to be a regular file + # symbolic links are handled in file_is_sane() + if [ ! -f "${fname}" -o -h "${fname}" ]; then + error_log "file is not a regular file: ${fname}" + return 1 + fi + + # root usually has access to write readonly files... + if [ ! -w "${fname}" ]; then + error_log "file is readonly: ${fname}" + return 1 + fi + + # Warn only + if [ -x "${fname}" ]; then + warn_log "file is executable: ${fname}" + fi +} + +# +# Prints list of files to stdout +# +get_banner_files () +{ + local flist=" \ + /etc/issue \ + /etc/issue.net \ + /etc/motd.head \ + /etc/motd.tail \ + " + + echo ${flist} +} + +# +# This is to be executed either by config_controller or by the user +# through apply_banner_customization +# +# For each customizable file, if a customization is present do a bit of +# sanity and copy the file to the platform config for banner +# customization. +# +# Return 0 on success +# Return 1 for error conditions, if any customization file failed sanity +# +customize_banner () +{ + if [ ! -d "${CONFIG_PATH}" ]; then + error_log "config path does not exist" + return 1 + fi + + banner_dir="$1" + if [ -z "${banner_dir}" ]; then + error_log "path containing customization files is required" + return 1 + fi + + if [ ! -d "${banner_dir}" ]; then + warn_log "directory does not exist: ${banner_dir}" + return 0 + fi + + local inputok=0 + local count=0 + local fname="" + for fname in $(get_banner_files); do { + local bname="$(basename $fname)" + # confname includes 'etc'; newfname does not. This seems easier + # for the user; at least until a file with a duplicate name is + # customizable + local confname="${PLATFORM_BANNER_DIR}/${fname}" + local newfname="${banner_dir}/${bname}" + + if [ -e "${newfname}" ]; then + count=$(expr $count + 1) + if ! file_is_sane ${newfname}; then + inputok=1 + continue + fi + + if [ -f "${confname}" ]; then + info_log "updating customization of ${fname}" + rm ${confname} + else + info_log "adding customization of ${fname}" + fi + + mkdir -p $(dirname ${confname}) + cp ${newfname} ${confname} + elif [ -f "${confname}" ]; then + info_log "maintaining previous customization of ${fname}" + fi + }; done + + if [ "$count" -eq 0 ]; then + warn_log "no customization files were found in $banner_dir" + fi + + return $inputok +} + +# +# Compare two banner files +# +# Return 0 if they are the same +# 1 if they are different +# +compare_file () +{ + diff -q "$1" "$2" 2>&1 > /dev/null + return $? +} + +# +# copy the file with a bkx extension, but only if it is not identical to +# another; look for an unused filename +# +# put a hard limit on the number of iterations +# +backup_file () +{ + local fname=$1 + local dname=$(dirname $fname) + local bname=$(basename $fname) + local bkdir=${OPT_BANNER_BACKUP}/${dname} + local count=0 + local newname="" + + if [ ! -f "${fname}" ]; then + warn_log "file does not exist: $fname" + return 0 + fi + + for count in $(seq 0 9); do { + newname=${bkdir}/${bname}.bk${count} + if [ -e "${newname}" ]; then + if compare_file "${newname}" "${fname}"; then + info_log "file is previously backed up ${fname} as ${newname}" + touch ${newname} + return 0 + fi + + info_log "skipping name ${newname}" + else + if [ "$count" -gt 7 ]; then + warn_log "consider cleaning up $(dirname ${newname})" + fi + + info_log "backing up ${fname} as ${newname}" + mkdir -p ${bkdir} + cp ${fname} ${newname} + return 0 + fi + }; done + + # find the oldest file and delete it. + newname=$(find ${bkdir} -maxdepth 1 -type f -name "${bname}.bk[0-9]" \ + | xargs -r ls -1t | tail -n 1) + if [ -z "${newname}" -o ! -f "${newname}" ]; then + error_log "did not find backup files for ${fname}" + return 1 + fi + + warn_log "deleting oldest backed up file ${newname}" + rm ${newname} + cp ${fname} ${newname} + + return $? +} + +# +# For each customizable file, if the file exists under +# PLATFORM_BANNER_DIR, and it passes some sanity checks, then install +# the file onto the root fs +# +install_banner_files () +{ + # quietly stop if the PLATFORM_BANNER_DIR is not setup + if [ ! -d ${PLATFORM_BANNER_DIR} ]; then + return 0 + fi + + local banner_files=$(get_banner_files) + local bfile="" + for bfile in ${banner_files}; do { + # do not attempt to install files if the directory on the root + # fs is absent; this is an unexpected condition + if [ ! -d "$(dirname ${bfile})" ]; then + error_log "directory does not exist for ${bfile}" + continue + fi + + # proceed only if the user provided a customization for the file + if [ ! -f "${PLATFORM_BANNER_DIR}/${bfile}" ]; then + info_log "file is not customized: ${bfile}" + continue + fi + + if [ -e "${bfile}" ]; then + if ! file_is_sane ${bfile}; then + continue + fi + if compare_file "${PLATFORM_BANNER_DIR}/${bfile}" "${bfile}"; then + info_log "file already installed: ${bfile}" + continue + fi + info_log "installing over existing file: ${bfile}" + backup_file ${bfile} \ + || continue + else + info_log "installing: ${bfile}" + fi + + cp ${PLATFORM_BANNER_DIR}/${bfile} ${bfile} + }; done; +} diff --git a/utilities/update-motd/files/install_banner_customization b/utilities/update-motd/files/install_banner_customization new file mode 100644 index 00000000..f7850b92 --- /dev/null +++ b/utilities/update-motd/files/install_banner_customization @@ -0,0 +1,16 @@ +#!/bin/bash + +# +# Copyright (c) 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +. /usr/sbin/customize-banner + +install_banner_files + +# recreate /etc/motd +/usr/sbin/motd-update + +exit 0 diff --git a/utilities/update-motd/files/motd-footer b/utilities/update-motd/files/motd-footer new file mode 100644 index 00000000..02d6beb5 --- /dev/null +++ b/utilities/update-motd/files/motd-footer @@ -0,0 +1,16 @@ +#!/bin/sh + +# +# Copyright (c) 2014-2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# motd.tail is reserved for the admin to append static +# trailing information to a dynamically generated +# /etc/motd. +# +# To add dynamic information, add a numbered +# script to /etc/motd.d/ + +[ -f /etc/motd.tail ] && cat /etc/motd.tail || true diff --git a/utilities/update-motd/files/motd-header b/utilities/update-motd/files/motd-header new file mode 100644 index 00000000..f0edde82 --- /dev/null +++ b/utilities/update-motd/files/motd-header @@ -0,0 +1,16 @@ +#!/bin/sh + +# +# Copyright (c) 2014-2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# motd.head is reserved for the admin to prepend +# static information to a dynamically generated +# /etc/motd. +# +# To add dynamic information, add a numbered +# script to /etc/motd.d/ + +[ -f /etc/motd.head ] && cat /etc/motd.head || true diff --git a/utilities/update-motd/files/motd-update b/utilities/update-motd/files/motd-update new file mode 100644 index 00000000..b853b09d --- /dev/null +++ b/utilities/update-motd/files/motd-update @@ -0,0 +1,15 @@ +#!/bin/bash + +# +# Copyright (c) 2014, 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +MOTD_FILE=${MOTD_FILE:-"/etc/motd"} +MOTD_PATH=${MOTD_PATH:-"/etc/motd.d"} +MOTD_TAG=${MOTD_TAG:-"motd-update"} + +if [ -d ${MOTD_PATH} ]; then + run-parts --without-progname ${MOTD_PATH} 1>${MOTD_FILE} +fi diff --git a/utilities/update-motd/files/motd-update.cron b/utilities/update-motd/files/motd-update.cron new file mode 100644 index 00000000..19fa6681 --- /dev/null +++ b/utilities/update-motd/files/motd-update.cron @@ -0,0 +1,3 @@ +# m h dom mon dow user command +0 * * * * root /usr/sbin/motd-update +