summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/restful/common.py
blob: 1b957d6b5ecfa3bd99f2e696f0c9494ec2271923 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# List of valid osd flags
OSD_FLAGS = [
    'pause', 'noup', 'nodown', 'noout', 'noin', 'nobackfill',
    'norecover', 'noscrub', 'nodeep-scrub',
]

# Implemented osd commands
OSD_IMPLEMENTED_COMMANDS = [
    'scrub', 'deep-scrub', 'repair'
]

# Valid values for the 'var' argument to 'ceph osd pool set'
POOL_PROPERTIES_1 = [
    'size', 'min_size', 'pg_num',
    'crush_rule', 'hashpspool',
]

POOL_PROPERTIES_2 = [
    'pgp_num'
]

POOL_PROPERTIES = POOL_PROPERTIES_1 + POOL_PROPERTIES_2

# Valid values for the 'ceph osd pool set-quota' command
POOL_QUOTA_PROPERTIES = [
    ('quota_max_bytes', 'max_bytes'),
    ('quota_max_objects', 'max_objects'),
]

POOL_ARGS = POOL_PROPERTIES + [x for x,_ in POOL_QUOTA_PROPERTIES]


# Transform command to a human readable form
def humanify_command(command):
    out = [command['prefix']]

    for arg, val in command.items():
        if arg != 'prefix':
            out.append("%s=%s" % (str(arg), str(val)))

    return " ".join(out)


def invalid_pool_args(args):
    invalid = []
    for arg in args:
        if arg not in POOL_ARGS:
            invalid.append(arg)

    return invalid


def pool_update_commands(pool_name, args):
    commands = [[], []]

    # We should increase pgp_num when we are re-setting pg_num
    if 'pg_num' in args and 'pgp_num' not in args:
        args['pgp_num'] = args['pg_num']

    # Run the first pool set and quota properties in parallel
    for var in POOL_PROPERTIES_1:
        if var in args:
            commands[0].append({
                'prefix': 'osd pool set',
                'pool': pool_name,
                'var': var,
                'val': args[var],
            })

    for (var, field) in POOL_QUOTA_PROPERTIES:
        if var in args:
            commands[0].append({
                'prefix': 'osd pool set-quota',
                'pool': pool_name,
                'field': field,
                'val': str(args[var]),
            })

    # The second pool set properties need to be run after the first wave
    for var in POOL_PROPERTIES_2:
        if var in args:
            commands[1].append({
                'prefix': 'osd pool set',
                'pool': pool_name,
                'var': var,
                'val': args[var],
            })

    return commands

def crush_rule_osds(node_buckets, rule):
    nodes_by_id = dict((b['id'], b) for b in node_buckets)

    def _gather_leaf_ids(node_id):
        if node_id >= 0:
            return set([node_id])

        result = set()
        for item in nodes_by_id[node_id]['items']:
            result |= _gather_leaf_ids(item['id'])

        return result

    def _gather_descendent_ids(node, typ):
        result = set()
        for item in node['items']:
            if item['id'] >= 0:
                if typ == "osd":
                    result.add(item['id'])
            else:
                child_node = nodes_by_id[item['id']]
                if child_node['type_name'] == typ:
                    result.add(child_node['id'])
                elif 'items' in child_node:
                    result |= _gather_descendent_ids(child_node, typ)

        return result

    def _gather_osds(root, steps):
        if root['id'] >= 0:
            return set([root['id']])

        osds = set()
        step = steps[0]
        if step['op'] == 'choose_firstn':
            # Choose all descendents of the current node of type 'type'
            descendent_ids = _gather_descendent_ids(root, step['type'])
            for node_id in descendent_ids:
                if node_id >= 0:
                    osds.add(node_id)
                else:
                    osds |= _gather_osds(nodes_by_id[node_id], steps[1:])
        elif step['op'] == 'chooseleaf_firstn':
            # Choose all descendents of the current node of type 'type',
            # and select all leaves beneath those
            descendent_ids = _gather_descendent_ids(root, step['type'])
            for node_id in descendent_ids:
                if node_id >= 0:
                    osds.add(node_id)
                else:
                    for desc_node in nodes_by_id[node_id]['items']:
                        # Short circuit another iteration to find the emit
                        # and assume anything we've done a chooseleaf on
                        # is going to be part of the selected set of osds
                        osds |= _gather_leaf_ids(desc_node['id'])
        elif step['op'] == 'emit':
            if root['id'] >= 0:
                osds |= root['id']

        return osds

    osds = set()
    for i, step in enumerate(rule['steps']):
        if step['op'] == 'take':
            osds |= _gather_osds(nodes_by_id[step['item']], rule['steps'][i + 1:])
    return osds