This bug seems to be combination of problems on both client and server sides. So we may need to add pyhton-neutronclient and/or python-openstackclient as an affected component. I'll do that as soon as I manage to locate which one contains the client side bug. But this report will be good to track the overall problem.
First the reproduction:
openstack network qos policy create policy0
openstack network qos rule create policy0 --type minimum-bandwidth --min-kbps 1000 --egress # 71a84995-cccd-4f09-9c3d-b1caa18ff363
openstack network qos rule set policy0 71a84995-cccd-4f09-9c3d-b1caa18ff363 --min-kbps 1001 --egress
-> works as expected
# make sure we only have one rule of the type
openstack network qos rule delete policy0 71a84995-cccd-4f09-9c3d-b1caa18ff363
openstack network qos rule create policy0 --type minimum-bandwidth --min-kbps 1000 --ingress # 1155c1c8-f9a7-4954-b195-9f58c8e18b4d
openstack network qos rule set policy0 1155c1c8-f9a7-4954-b195-9f58c8e18b4d --min-kbps 1001 --ingress
-> works as expected
openstack network qos rule delete policy0 1155c1c8-f9a7-4954-b195-9f58c8e18b4d
# create the ingress/egress pair at once
openstack network qos rule create policy0 --type minimum-bandwidth --min-kbps 1000 --egress # f392837a-09e2-4b5e-8c29-86670797679e
openstack network qos rule create policy0 --type minimum-bandwidth --min-kbps 1000 --ingress # 77dae223-b787-4943-bb45-c42424fd29ec
# This is the bug. As we'll see later the trigger is a client-side problem, but I don't think neutron-server should return 500 Internal Server Error. The malformed input should be caught earlier and a 4xx response should be given.
openstack network qos rule set policy0 f392837a-09e2-4b5e-8c29-86670797679e --min-kbps 1001 --egress
Failed to set Network QoS rule ID "f392837a-09e2-4b5e-8c29-86670797679e": HttpException: 500: Server Error for url: http://100.109.0.20:9696/v2.0/qos/policies/188a2f59-ab90-41a3-9e6f-58e641a34544/minimum_bandwidth_rules/f392837a-09e2-4b5e-8c29-86670797679e, Request Failed: internal server error while processing your request.
openstack network qos rule set policy0 77dae223-b787-4943-bb45-c42424fd29ec --min-kbps 1001 --ingress
Failed to set Network QoS rule ID "77dae223-b787-4943-bb45-c42424fd29ec": HttpException: 500: Server Error for url: http://100.109.0.20:9696/v2.0/qos/policies/188a2f59-ab90-41a3-9e6f-58e641a34544/minimum_bandwidth_rules/77dae223-b787-4943-bb45-c42424fd29ec, Request Failed: internal server error while processing your request.
# the same rule update can be done by neutronclient, but only for the egress direction
neutron qos-minimum-bandwidth-rule-update f392837a-09e2-4b5e-8c29-86670797679e policy0 --min-kbps 1001 --direction egress
-> works as expected
# this failure is expected because neutronclient was long deprecated already when the ingress direction was introduced
neutron qos-minimum-bandwidth-rule-update 77dae223-b787-4943-bb45-c42424fd29ec policy0 --min-kbps 1001 --direction ingress
neutron qos-minimum-bandwidth-rule-update: error: argument --direction: invalid choice: u'ingress' (choose from 'egress')
Further details:
The working update by neutronclient looks like this:
neutron qos-minimum-bandwidth-rule-update f392837a-09e2-4b5e-8c29-86670797679e policy0 --min-kbps 1001 --direction egress
PUT /v2.0/qos/policies/188a2f59-ab90-41a3-9e6f-58e641a34544/minimum_bandwidth_rules/f392837a-09e2-4b5e-8c29-86670797679e
{"minimum_bandwidth_rule": {"direction": "egress", "min_kbps": "1001"}}
The wrong update by openstackclient looks like this:
openstack network qos rule set policy0 f392837a-09e2-4b5e-8c29-86670797679e --min-kbps 1001 --egress
PUT /v2.0/qos/policies/188a2f59-ab90-41a3-9e6f-58e641a34544/minimum_bandwidth_rules/f392837a-09e2-4b5e-8c29-86670797679e
{"minimum_bandwidth_rule": {"min_kbps": 1001}}
The 500 Internal Server Error's traceback:
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource [None req-e73566b0-35e0-4572-a3d5-28f77853b4c9 admin admin] update failed: No details.: AttributeError: 'QosMinimumBandwidthRule' object has no attribute '_ob
j_direction'
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource Traceback (most recent call last):
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/api/v2/resource.py", line 98, in resource
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource result = method(request=request, **args)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/api/v2/base.py", line 624, in update
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource return self._update(request, id, body, **kwargs)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron-lib/neutron_lib/db/api.py", line 142, in wrapped
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource setattr(e, '_RETRY_EXCEEDED', True)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_utils/excutils.py", line 220, in __exit__
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource self.force_reraise()
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_utils/excutils.py", line 196, in force_reraise
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource six.reraise(self.type_, self.value, self.tb)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron-lib/neutron_lib/db/api.py", line 138, in wrapped
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource return f(*args, **kwargs)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_db/api.py", line 154, in wrapper
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource ectxt.value = e.inner_exc
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_utils/excutils.py", line 220, in __exit__
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource self.force_reraise()
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_utils/excutils.py", line 196, in force_reraise
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource six.reraise(self.type_, self.value, self.tb)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_db/api.py", line 142, in wrapper
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource return f(*args, **kwargs)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron-lib/neutron_lib/db/api.py", line 198, in wrapped
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource LOG.debug("Retry wrapper got retriable exception: %s", e)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_utils/excutils.py", line 220, in __exit__
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource self.force_reraise()
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_utils/excutils.py", line 196, in force_reraise
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource six.reraise(self.type_, self.value, self.tb)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron-lib/neutron_lib/db/api.py", line 194, in wrapped
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource return f(*dup_args, **dup_kwargs)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/api/v2/base.py", line 680, in _update
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource obj = obj_updater(request.context, id, **kwargs)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/extensions/qos.py", line 174, in <lambda>
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource method_name, rule_cls, *args, **kwargs)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/extensions/qos.py", line 170, in _make_call
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource context, rule_cls, *args_list, **params
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/db/db_base_plugin_common.py", line 50, in inner
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource result = f(*args, **kwargs)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/services/qos/qos_plugin.py", line 423, in update_policy_rule
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource checker.check_rules_conflict(policy, rule)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/objects/qos/qos_policy_validator.py", line 63, in check_rules_conflict
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource if rule.duplicates(rule_obj):
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/opt/stack/neutron/neutron/objects/qos/rule.py", line 83, in duplicates
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource if getattr(self, field) != getattr(other_rule, field):
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource File "/usr/local/lib/python2.7/dist-packages/oslo_versionedobjects/base.py", line 68, in getter
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource return getattr(self, attrname)
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource AttributeError: 'QosMinimumBandwidthRule' object has no attribute '_obj_direction'
febr 12 12:20:19 devstack0 neutron-server[31565]: ERROR neutron.api.v2.resource·
The version used to reproduce the bug:
neutron 2f3cc51784
neutron-lib aceb7c50ed
devstack ee4b6a01
python-openstackclient dcff1012fd
python-neutronclient d74b871f7fe
openstacksdk==0.23.0
osc-lib==1.12.0
I'll work on fixing these problems.
Quick summary of my findings so far:
At the time of reporting I thought this is a combination of client and server side bugs. But now I think this should be fixed purely on server side.
My original thinking was based on the fact that neutronclient can update a qos rule, while osc cannot. And my first attempt for a fix was to get osc to send the same body as neutronclient does.
But if you take a closer look at the PUT bodies sent by both clients, you may ask why neutron-server mandates the presence of the direction field in the body even when the direction field is not being updated? We only want to update min_kbps here. So the body sent by osc should be accepted by neutron-server as a valid request.
While debugging I also realized it's practically impossible to get osc (ie. openstacksdk more precisely) to send the same body as neutronclient does. The basic reason is the logic in the _update() method here:
https:/ /github. com/openstack/ openstacksdk/ blob/master/ openstack/ proxy.py# L178
Instead of sending a single PUT, it first GETs the resource and only includes the changed fields into the PUT body. By that it does not care if '[--ingress| --egress] ' was present on the command line as long as the direction field's value does not change. In the source I don't see a way to force the inclusion a field that didn't change. So with the current openstacksdk I don't think this can be fixed on the client side.
Anyway there's an easy workaround if someone is willing to fiddle with curl:
$ cat min-bw-rule-update
#! /bin/sh
# export TOKEN="$( openstack token issue -f value -c id )" 127.0.0. 1:9696 188a2f59- ab90-41a3- 9e6f-58e641a345 44 f392837a- 09e2-4b5e- 8c29-8667079767 9e egress 1001
# min-bw-rule-update NEUTRON-BASE-URL POLICY-ID RULE-ID DIRECTION MIN-KBPS
# min-bw-rule-update http://
neutron_ base_url= "${1:?} "
policy_id="${2:?}"
rule_id="${3:?}"
direction="${4:?}"
min_kbps="${5:?}"
cat <<EOF | bandwidth_ rule": neutron_ base_url: ?}/v2.0/ qos/policies/ $policy_ id/minimum_ bandwidth_ rules/$ rule_id" \
{"minimum_
{"direction": "$direction",
"min_kbps": "$min_kbps"}}
EOF
curl \
--silent \
--insecure \
--request PUT \
--header "content-type: application/json" \
--header "x-auth-token: ${TOKEN:?}" \
--data @- \
"${
| json_pp
lajoskatona told me he's looking into the server side of this bug, the next update may be coming from him.