-
Notifications
You must be signed in to change notification settings - Fork 390
/
vrouter_scheduler.py
153 lines (127 loc) · 5.64 KB
/
vrouter_scheduler.py
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
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2014 Cloudwatt
# All Rights Reserved.
#
# 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.
#
# @author: Edouard Thuleau, Cloudwatt.
import abc
import ast
from distutils.version import StrictVersion as V
import random
import six
from cfgm_common import analytics_client
from cfgm_common import svc_info
from vnc_api.vnc_api import NoIdError
@six.add_metaclass(abc.ABCMeta)
class VRouterScheduler(object):
def __init__(self, vnc_lib, args):
self._vnc_lib = vnc_lib
self._args = args
# initialize analytics client
endpoint = "http://%s:%s" % (self._args.analytics_server_ip,
self._args.analytics_server_port)
self._analytics = analytics_client.Client(endpoint)
@abc.abstractmethod
def schedule(self, plugin, context, router_id, candidates=None):
"""Schedule the virtual machine to an active vrouter agent.
Schedule the virtual machine only if it is not already scheduled and
there is no other virtual machines of the same service instance already
scheduled on the vrouter.
"""
pass
def _get_candidates(self, si_uuid, vm_uuid):
"""Return vrouter agents where a service instance virtual machine
could be scheduled.
If a VM of a same service instance is already scheduled on the vrouter,
that vrouter is exclude from the candidates list.
If the VM is already scheduled on a running vrouter, only that vrouter
is return in the candidates list.
"""
vrs_fq_name = [vr['fq_name'] for vr in
self._vnc_lib.virtual_routers_list()['virtual-routers']
if self.vrouter_running(vr['fq_name'][-1])]
vrs_fq_name = [vr_fq_name for vr_fq_name in vrs_fq_name
if self.vrouter_check_version(
vr_fq_name[-1],
svc_info._VROUTER_NETNS_SUPPORTED_VERSION)]
for vr_fq_name in vrs_fq_name:
try:
vr_obj = self._vnc_lib.virtual_router_read(fq_name=vr_fq_name)
except NoIdError:
vrs_fq_name.remove(vr_fq_name)
continue
for vm_ref in vr_obj.get_virtual_machine_refs() or []:
if vm_uuid == vm_ref['uuid']:
return [vr_fq_name]
try:
vm_obj = self._vnc_lib.virtual_machine_read(
id=vm_ref['uuid'])
except NoIdError:
continue
if si_uuid in [si['uuid'] for si in
vm_obj.get_service_instance_refs()]:
vrs_fq_name.remove(vr_fq_name)
continue
return vrs_fq_name
def vrouter_running(self, vrouter_name):
"""Check if a vrouter agent is up and running."""
path = "/analytics/uves/vrouter/"
fqdn_uuid = "%s?cfilt=NodeStatus" % vrouter_name
try:
vrouter_status = self._analytics.request(path, fqdn_uuid)
except analytics_client.OpenContrailAPIFailed:
return False
if not vrouter_status or 'NodeStatus' not in vrouter_status or \
'process_status' not in vrouter_status['NodeStatus']:
return False
for process in vrouter_status['NodeStatus']['process_status']:
if (process['module_id'] == 'VRouterAgent' and
int(process['instance_id']) == 0 and
process['state'] == 'Functional'):
return True
return False
def vrouter_check_version(self, vrouter_name, version):
"""Check the vrouter version is upper or equal to a desired version."""
path = "/analytics/uves/vrouter/"
fqdn_uuid = "%s?cfilt=VrouterAgent" % vrouter_name
try:
vrouter_agent = self._analytics.request(path, fqdn_uuid)
except analytics_client.OpenContrailAPIFailed:
return False
if not vrouter_agent:
return False
try:
build_info = ast.literal_eval(
vrouter_agent['VrouterAgent']['build_info'])
vrouter_version = V(build_info['build-info'][0]['build-version'])
requested_version = V(version)
except KeyError, ValueError:
return False
return vrouter_version >= requested_version
def _bind_vrouter(self, vm_uuid, vr_fq_name):
"""Bind the virtual machine to the vrouter which has been chosen."""
vm_obj = self._vnc_lib.virtual_machine_read(id=vm_uuid)
vr_obj = self._vnc_lib.virtual_router_read(fq_name=vr_fq_name)
vr_obj.add_virtual_machine(vm_obj)
self._vnc_lib.virtual_router_update(vr_obj)
class RandomScheduler(VRouterScheduler):
"""Randomly allocate a vrouter agent for virtual machine of a service
instance."""
def schedule(self, si_uuid, vm_uuid):
candidates = self._get_candidates(si_uuid, vm_uuid)
if not candidates:
return
chosen_vrouter = random.choice(candidates)
self._bind_vrouter(vm_uuid, chosen_vrouter)
return chosen_vrouter