From 1e2ba282ce0dce256e0506905812d8bdfb4922e0 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Mon, 15 Aug 2016 11:12:48 +0300 Subject: [PATCH] api_reply support for QoS migration Copy QoS policies and rules from source setup to destination (NSX-V3) client And also copy network/port policy-id. Change-Id: I76ec0ceefe618e9bf6ea7cf61bcdb07c4edbdddb --- vmware_nsx/api_replay/client.py | 83 ++++++++++++++++++- vmware_nsx/extensions/api_replay.py | 7 ++ .../services/qos/nsx_v3/message_queue.py | 2 +- 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/vmware_nsx/api_replay/client.py b/vmware_nsx/api_replay/client.py index c6940f825b..9c0ea8a12a 100644 --- a/vmware_nsx/api_replay/client.py +++ b/vmware_nsx/api_replay/client.py @@ -45,6 +45,7 @@ class ApiReplayClient(object): auth_url=self._dest_os_auth_url) self.migrate_security_groups() + self.migrate_qos_policies() self.migrate_routers() self.migrate_networks_subnets_ports() self.migrate_floatingips() @@ -90,6 +91,81 @@ class ApiReplayClient(object): body[k] = v return body + def migrate_qos_rule(self, dest_policy, source_rule): + """Add the QoS rule from the source to the QoS policy + + If there is already a rule of that type, skip it since + the QoS policy can have only one rule of each type + """ + #TODO(asarfaty) also take rule direction into account once + #ingress support is upstream + rule_type = source_rule.get('type') + dest_rules = dest_policy.get('rules') + if dest_rules: + for dest_rule in dest_rules: + if dest_rule['type'] == rule_type: + return + pol_id = dest_policy['id'] + drop_qos_rule_fields = ['revision', 'type', 'qos_policy_id', 'id'] + body = self.drop_fields(source_rule, drop_qos_rule_fields) + try: + if rule_type == 'bandwidth_limit': + rule = self.dest_neutron.create_bandwidth_limit_rule( + pol_id, body={'bandwidth_limit_rule': body}) + elif rule_type == 'dscp_marking': + rule = self.dest_neutron.create_dscp_marking_rule( + pol_id, body={'dscp_marking_rule': body}) + else: + print("QoS rule type %s is not supported for policy %s" % ( + rule_type, pol_id)) + print("created QoS policy %s rule %s " % (pol_id, rule)) + except Exception as e: + print("Failed to create QoS rule for policy %s: %s" % (pol_id, e)) + + def migrate_qos_policies(self): + """Migrates QoS policies from source to dest neutron.""" + + # first fetch the QoS policies from both the + # source and destination neutron server + try: + source_qos_pols = self.source_neutron.list_qos_policies()[ + 'policies'] + except n_exc.NotFound: + # QoS disabled on source + return + try: + dest_qos_pols = self.dest_neutron.list_qos_policies()['policies'] + except n_exc.NotFound: + # QoS disabled on dest + print("QoS is disabled on destination: ignoring QoS policies") + return + + drop_qos_policy_fields = ['revision'] + + for pol in source_qos_pols: + dest_pol = self.have_id(pol['id'], dest_qos_pols) + # If the policy already exists on the the dest_neutron + if dest_pol: + # make sure all the QoS policy rules are there and + # create them if not + for qos_rule in pol['rules']: + self.migrate_qos_rule(dest_pol, qos_rule) + + # dest server doesn't have the group so we create it here. + else: + qos_rules = pol.pop('rules') + try: + body = self.drop_fields(pol, drop_qos_policy_fields) + new_pol = self.dest_neutron.create_qos_policy( + body={'policy': body}) + except Exception as e: + print("Failed to create QoS policy %s: %s" % ( + pol['id'], e)) + continue + print("Created QoS policy %s" % new_pol) + for qos_rule in qos_rules: + self.migrate_qos_rule(new_pol['policy'], qos_rule) + def migrate_security_groups(self): """Migrates security groups from source to dest neutron.""" @@ -197,15 +273,14 @@ class ApiReplayClient(object): 'port_security_enabled', 'binding:vif_details', 'binding:vif_type', - 'binding:host_id', 'qos_policy_id', + 'binding:host_id', 'revision', 'vnic_index'] drop_network_fields = ['status', 'subnets', 'availability_zones', 'created_at', 'updated_at', 'tags', - 'qos_policy_id', 'ipv4_address_scope', - 'ipv6_address_scope', 'mtu', - 'revision'] + 'ipv4_address_scope', 'ipv6_address_scope', + 'mtu', 'revision'] for network in source_networks: body = self.drop_fields(network, drop_network_fields) diff --git a/vmware_nsx/extensions/api_replay.py b/vmware_nsx/extensions/api_replay.py index 4fec4d443d..be5681d0ee 100644 --- a/vmware_nsx/extensions/api_replay.py +++ b/vmware_nsx/extensions/api_replay.py @@ -47,6 +47,9 @@ RESOURCE_ATTRIBUTE_MAP = { 'routers': { 'id': ID_WITH_POST, }, + 'policies': { # QoS policies + 'id': ID_WITH_POST, + }, } @@ -79,3 +82,7 @@ class Api_replay(extensions.ExtensionDescriptor): # make sure this extension is called after those, so our change # will not be overridden return ["security-group", "router"] + + def get_optional_extensions(self): + # QoS is optional since it is not always enabled + return ["qos"] diff --git a/vmware_nsx/services/qos/nsx_v3/message_queue.py b/vmware_nsx/services/qos/nsx_v3/message_queue.py index a155fdb5de..908ff7c13d 100644 --- a/vmware_nsx/services/qos/nsx_v3/message_queue.py +++ b/vmware_nsx/services/qos/nsx_v3/message_queue.py @@ -26,4 +26,4 @@ class NsxV3QosNotificationDriver( """ def create_policy(self, context, policy): - self.notification_api.push(context, policy, events.CREATED) + self.notification_api.push(context, [policy], events.CREATED)