Add list-crush-rules action
This action provides a list of crush rules defined in CEPH clusters. Closes-bug: #1957458 Change-Id: I2a5fdae776e00d869a624e1107ab42cf69bb2f50
This commit is contained in:
parent
c07fb2dc6a
commit
37105f11cd
12
actions.yaml
12
actions.yaml
@ -405,3 +405,15 @@ get-quorum-status:
|
||||
- text
|
||||
- json
|
||||
description: Specify output format (text|json).
|
||||
list-crush-rules:
|
||||
description: "List CEPH crush rules"
|
||||
params:
|
||||
format:
|
||||
type: string
|
||||
enum:
|
||||
- json
|
||||
- yaml
|
||||
- text
|
||||
default: text
|
||||
description: "The output format, either json, yaml or text (default)"
|
||||
additionalProperties: false
|
||||
|
1
actions/list-crush-rules
Symbolic link
1
actions/list-crush-rules
Symbolic link
@ -0,0 +1 @@
|
||||
list_crush_rules.py
|
76
actions/list_crush_rules.py
Executable file
76
actions/list_crush_rules.py
Executable file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2022 Canonical Ltd
|
||||
#
|
||||
# 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.
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
from subprocess import check_output, CalledProcessError
|
||||
|
||||
_path = os.path.dirname(os.path.realpath(__file__))
|
||||
_hooks = os.path.abspath(os.path.join(_path, "../hooks"))
|
||||
|
||||
|
||||
def _add_path(path):
|
||||
if path not in sys.path:
|
||||
sys.path.insert(1, path)
|
||||
|
||||
|
||||
_add_path(_hooks)
|
||||
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
ERROR,
|
||||
log,
|
||||
function_fail,
|
||||
function_get,
|
||||
function_set
|
||||
)
|
||||
|
||||
|
||||
def get_list_crush_rules(output_format="text"):
|
||||
"""Get list of Ceph crush rules.
|
||||
|
||||
:param output_format: specify output format
|
||||
:type output_format: str
|
||||
:returns: text: list of tuple (<rule_id> <rule_name>) or
|
||||
yaml: list of crush rules in yaml format
|
||||
json: list of crush rules in json format
|
||||
:rtype: str
|
||||
"""
|
||||
crush_rules = check_output(["ceph", "--id", "admin", "osd", "crush",
|
||||
"rule", "dump", "-f", "json"]).decode("UTF-8")
|
||||
crush_rules = json.loads(crush_rules)
|
||||
|
||||
if output_format == "text":
|
||||
return ",".join(["({}, {})".format(rule["rule_id"], rule["rule_name"])
|
||||
for rule in crush_rules])
|
||||
elif output_format == "yaml":
|
||||
return yaml.dump(crush_rules)
|
||||
else:
|
||||
return json.dumps(crush_rules)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
list_crush_rules = get_list_crush_rules(function_get("format"))
|
||||
function_set({"message": list_crush_rules})
|
||||
except CalledProcessError as error:
|
||||
log(error, ERROR)
|
||||
function_fail("List crush rules failed with error: {}".format(error))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -34,5 +34,4 @@ class ReweightTestCase(CharmTestCase):
|
||||
osd_num = 4
|
||||
new_weight = 1.2
|
||||
action.crush_reweight(osd_num, new_weight)
|
||||
print(_reweight_osd.calls)
|
||||
_reweight_osd.assert_has_calls([mock.call("4", "1.2")])
|
||||
|
155
unit_tests/test_action_list_crush_rules.py
Normal file
155
unit_tests/test_action_list_crush_rules.py
Normal file
@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2022 Canonical Ltd
|
||||
#
|
||||
# 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.
|
||||
import json
|
||||
import yaml
|
||||
|
||||
from actions import list_crush_rules
|
||||
from test_utils import CharmTestCase
|
||||
|
||||
|
||||
class ListCrushRulesTestCase(CharmTestCase):
|
||||
ceph_osd_crush_rule_dump = b"""
|
||||
[
|
||||
{
|
||||
"rule_id": 0,
|
||||
"rule_name": "replicated_rule",
|
||||
"ruleset": 0,
|
||||
"type": 1,
|
||||
"min_size": 1,
|
||||
"max_size": 10,
|
||||
"steps": [
|
||||
{
|
||||
"op": "take",
|
||||
"item": -1,
|
||||
"item_name": "default"
|
||||
},
|
||||
{
|
||||
"op": "chooseleaf_firstn",
|
||||
"num": 0,
|
||||
"type": "host"
|
||||
},
|
||||
{
|
||||
"op": "emit"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rule_id": 1,
|
||||
"rule_name": "test-host",
|
||||
"ruleset": 1,
|
||||
"type": 1,
|
||||
"min_size": 1,
|
||||
"max_size": 10,
|
||||
"steps": [
|
||||
{
|
||||
"op": "take",
|
||||
"item": -1,
|
||||
"item_name": "default"
|
||||
},
|
||||
{
|
||||
"op": "chooseleaf_firstn",
|
||||
"num": 0,
|
||||
"type": "host"
|
||||
},
|
||||
{
|
||||
"op": "emit"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rule_id": 2,
|
||||
"rule_name": "test-chassis",
|
||||
"ruleset": 2,
|
||||
"type": 1,
|
||||
"min_size": 1,
|
||||
"max_size": 10,
|
||||
"steps": [
|
||||
{
|
||||
"op": "take",
|
||||
"item": -1,
|
||||
"item_name": "default"
|
||||
},
|
||||
{
|
||||
"op": "chooseleaf_firstn",
|
||||
"num": 0,
|
||||
"type": "chassis"
|
||||
},
|
||||
{
|
||||
"op": "emit"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rule_id": 3,
|
||||
"rule_name": "test-rack-hdd",
|
||||
"ruleset": 3,
|
||||
"type": 1,
|
||||
"min_size": 1,
|
||||
"max_size": 10,
|
||||
"steps": [
|
||||
{
|
||||
"op": "take",
|
||||
"item": -2,
|
||||
"item_name": "default~hdd"
|
||||
},
|
||||
{
|
||||
"op": "chooseleaf_firstn",
|
||||
"num": 0,
|
||||
"type": "rack"
|
||||
},
|
||||
{
|
||||
"op": "emit"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(ListCrushRulesTestCase, self).setUp(
|
||||
list_crush_rules, ["check_output", "function_fail", "function_get",
|
||||
"function_set"])
|
||||
self.function_get.return_value = "json" # format=json
|
||||
self.check_output.return_value = self.ceph_osd_crush_rule_dump
|
||||
|
||||
def test_getting_list_crush_rules_text_format(self):
|
||||
"""Test getting list of crush rules in text format."""
|
||||
self.function_get.return_value = "text"
|
||||
list_crush_rules.main()
|
||||
self.function_get.assert_called_once_with("format")
|
||||
self.function_set.assert_called_once_with(
|
||||
{"message": "(0, replicated_rule),(1, test-host),"
|
||||
"(2, test-chassis),(3, test-rack-hdd)"})
|
||||
|
||||
def test_getting_list_crush_rules_json_format(self):
|
||||
"""Test getting list of crush rules in json format."""
|
||||
crush_rules = self.ceph_osd_crush_rule_dump.decode("UTF-8")
|
||||
crush_rules = json.loads(crush_rules)
|
||||
self.function_get.return_value = "json"
|
||||
list_crush_rules.main()
|
||||
self.function_get.assert_called_once_with("format")
|
||||
self.function_set.assert_called_once_with(
|
||||
{"message": json.dumps(crush_rules)})
|
||||
|
||||
def test_getting_list_crush_rules_yaml_format(self):
|
||||
"""Test getting list of crush rules in yaml format."""
|
||||
crush_rules = self.ceph_osd_crush_rule_dump.decode("UTF-8")
|
||||
crush_rules = json.loads(crush_rules)
|
||||
self.function_get.return_value = "yaml"
|
||||
list_crush_rules.main()
|
||||
self.function_get.assert_called_once_with("format")
|
||||
self.function_set.assert_called_once_with(
|
||||
{"message": yaml.dump(crush_rules)})
|
Loading…
Reference in New Issue
Block a user