感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如有转载,请保留源作者博客信息。
如需交流,欢迎大家博客留言。
class UpdateHostMembersAction(workflows.MembershipAction):
def __init__(self, request, *args, **kwargs):
super(UpdateHostMembersAction, self).__init__(request, *args, **kwargs)
err_msg = _('Unable to retrieve user list. Please try again later.') #定义错误提示信息
#下面5行代码可以直接使用,复制粘贴即可
default_role_field_name = self.get_default_role_field_name()
self.fields[default_role_field_name] = forms.CharField(required=False)
self.fields[default_role_field_name].initial = 'member' #此处定义了一个
member名字供步骤7中contribute获取数据
field_name = self.get_member_field_name('member')
self.fields[field_name] = forms.MultipleChoiceField(required=False)
tenant_id = self.initial['tenant_id'] #此处获取url中的
tenant_id
isolated_scheduler_hosts = []
try:
#通过api从数据库获取当前租户所有可用的hosts(即图1-2的右边选择框)
isolated_scheduler_hosts = api.nova.get_isolated_scheduler_list(request, tenant_id, type="host")
except Exception:
exceptions.handle(request, err_msg)
enabled_host_names = [(host.isolated_name) for host in isolated_scheduler_hosts]
hosts = []
try: #此处获取所有可供选择的hosts,即图1-2中的左右之和
hosts = api.nova.host_list(request)
except Exception:
exceptions.handle(request, err_msg)
host_names = []
for host in hosts:
if host.host_name not in host_names and host.service == u'compute':
host_names.append(host.host_name)
host_names.sort()
all_names = [(host_name, host_name) for host_name in host_names]
#if sql table isolated_scheduler don't have any record, then all host is available
if len(enabled_host_names) == 0:
enabled_host_names = [(host_name) for host_name in host_names]
self.fields[field_name].choices = all_names #此处将图1-2中左右之和复制给
choices
self.fields[field_name].initial = enabled_host_names #此处将图1-2中右边已选择框中的值赋值给
initial
#通过上述两个赋值操作,则框架自动会将数据渲染到页面
class Meta:
name = _("UpdateHostMembers") #标签页的名字定义
slug = "UpdateHostMembers"
|
all_names = [(u'mynode158', u'mynode158'), (u'node10_31', u'node10_31'),(u'mynode1581', u'mynode1581'), (u'node10_311', u'node10_311'),(u'mynode1581', u'mynode1581'), (u'node10_311', u'node10_311')]
enabled_host_names = [(u'mynode158'), (u'node10_31')]
self.fields[field_name].choices = all_names
self.fields[field_name].initial = enabled_host_names
其中
initial
的初值只能有名字。
all_names 数据结构为 [(u'mynode158', u'mynode158')] 而enabled_host_names 数据结构为 [(u'mynode158')],数据结构错误则渲染不出来
|
class UpdateIsolation(workflows.Workflow):
slug = "update_isolation"
name = _("Edit Isolation")
finalize_button_name = _("Save")
success_message = _('Modified isolation "%s".')
failure_message = _('Unable to modify isolation "%s".')
success_url = "horizon:admin:isolations:index"
default_steps = (UpdateZoneMembers, UpdateAggregateMembers,UpdateHostMembers,)
def format_status_message(self, message):
return message % self.context.get('name', 'unknown isolation')
def handle(self, request, data):
tenant_id = data['tenant_id'] #获取
tenant_id
################################################################################################
#此处获取图1-2中右侧选择框中的数据。此处数据的初始化在步骤7中的contribute
selected_host_names = self.context['enabled_host_names']
enabled_host_names = []
try:
# 此处获取隔离调度数据库表中已有的hosts
enabled_hosts = api.nova.get_isolated_scheduler_list(request, tenant_id, type="host")
enabled_host_names = [(host.isolated_name) for host in enabled_hosts]
except Exception:
exceptions.handle(request, "get hosts exception")
try:
all_host_names = list(set(selected_host_names + enabled_host_names))
#重点:此处将前端页面图1-2右侧选择的,与底层数据库实际存在的做操作,即得到本次操作减少的或者增加的hsots,从而获取进行处理
host_add_list = list(set(all_host_names) - set(enabled_host_names))
host_remove_list = list(set(all_host_names) - set(selected_host_names))
tenant = api.keystone.tenant_get(request, tenant_id)
tenant_name = tenant.name
for host_name in host_add_list:#将上述得到新增host的列表,调用添加api添加到底层数据库持久化,此api更多跟进参考步骤10
api.nova.isolatation_add_host(request, host_name, tenant_id, tenant_name)
for host_name in host_remove_list:
#将上述得到减少host的列表,调用添加api添加到底层数据库持久化
api.nova.isolatation_remove_host(request, host_name, tenant_id, tenant_name)
except Exception:
exceptions.handle(request, "modify the hosts with tenant exception")
#以下为处理aggregate与zones原理与host处理一致,不再重复讲解
#################################################################################################
selected_aggregate_names = self.context['enabled_aggregate_names']
enabled_aggregate_names = []
try:
enabled_aggregates = api.nova.get_isolated_scheduler_list(request, tenant_id, type="aggregate")
enabled_aggregate_names = [(aggregate.isolated_name) for aggregate in enabled_aggregates]
except Exception:
exceptions.handle(request, "get aggregates exception")
try:
all_aggregate_names = list(set(selected_aggregate_names + enabled_aggregate_names))
aggregate_add_list = list(set(all_aggregate_names) - set(enabled_aggregate_names))
aggregate_remove_list = list(set(all_aggregate_names) - set(selected_aggregate_names))
tenant = api.keystone.tenant_get(request, tenant_id)
tenant_name = tenant.name
for aggregate_name in aggregate_add_list:
api.nova.isolatation_add_aggregate(request, aggregate_name, tenant_id, tenant_name)
for aggregate_name in aggregate_remove_list:
api.nova.isolatation_remove_aggregate(request, aggregate_name, tenant_id, tenant_name)
except Exception:
exceptions.handle(request, "modify the aggregates with tenant exception")
#################################################################################################
selected_zone_names = self.context['enabled_zone_names']
enabled_zone_names = []
try:
enabled_zones = api.nova.get_isolated_scheduler_list(request, tenant_id, type="zone")
enabled_zone_names = [(zone.isolated_name) for zone in enabled_zones]
except Exception:
exceptions.handle(request, "get zones exception")
try:
all_zone_names = list(set(selected_zone_names + enabled_zone_names))
zone_add_list = list(set(all_zone_names) - set(enabled_zone_names))
zone_remove_list = list(set(all_zone_names) - set(selected_zone_names))
tenant = api.keystone.tenant_get(request, tenant_id)
tenant_name = tenant.name
for zone_name in zone_add_list:
api.nova.isolatation_add_zone(request, zone_name, tenant_id, tenant_name)
for zone_name in zone_remove_list:
api.nova.isolatation_remove_zone(request, zone_name, tenant_id, tenant_name)
except Exception:
exceptions.handle(request, "modify the zones with tenant exception")
return True
|
member_actions={"action": "POST","list_hosts_by_tenant_id":"GET",
"get_isolated_scheduler_zone_list":"GET",
"get_isolated_scheduler_aggregate_list":"GET",
"get_isolated_scheduler_host_list":"GET"})
|
curl -i ' http://192.168.10.31
:8774/v2/2a4fe5e733e44982b1d576c5a0fe4bfd/
os-isolation-hosts/
2a4fe5e733e44982b1d576c5a0fe4bfd
/action' -X POST -H "User-Agent: python-novaclient" -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Auth-Token: $TOKEN" -d '{"add_host": {"isolated_name": "node31","tenant_name":"admin"}}'
|
def get_isolatedname_and_username_from_body(fn):
"""Makes sure that the host exists."""
def wrapped(self, req, id, body, *args, **kwargs):
if len(body) == 2 and "isolated_name" in body and "tenant_name" in body:
isolated_name = body['isolated_name']
tenant_name = body['tenant_name']
else:
raise exc.HTTPBadRequest()
return fn(self, req, id, isolated_name, tenant_name , *args, **kwargs)
return wrapped
|
# add by ttx 2014-9-17
@require_context
def add_host_to_isolation(context, tenant_id, tenant_name, isolated_name, isolated_id):
#此处代码判断是否在数据库中已经存在该条数据,只是被soft_delete掉(即图7-1中所示),此处代码参考步骤8
result = get_isolation_query(context, tenant_id, isolated_name, 0)
if result: #如果已经存在被软删除过的数据,则将deleted更新为0即可
values = {
'updated_at': timeutils.datetime.datetime.utcnow(),
'deleted_at' : None,
'deleted' : 0}
result.update(values) #构造一个更新数据字典
result.save() #更新数据
else: #假若数据库没有任何记录,则直接新增
session = get_session()
values = {'tenant_id': tenant_id,
'tenant_name': tenant_name,
'project_id': context.project_id,
'isolated_type': '0',
'isolated_name': isolated_name,
'isolated_id': isolated_id,
'created_at':timeutils.datetime.datetime.utcnow()}
isolation_ref = models.IsolatedSchedule()
isolation_ref.update(values)
session.add(isolation_ref)
session.flush()#新增完之后需要执行flush才能立即写入到数据库
|
#isolated_type 0==host 1==aggregate 2=zone
def get_isolation_query(context, tenant_id, isolated_name, isolated_type):
result = model_query(context, models.IsolatedSchedule, read_deleted="only").\
filter_by(tenant_id=tenant_id).\
filter_by(isolated_name=isolated_name).\
filter_by(isolated_type=isolated_type).\
first()
return result
|
# add by ttx 2014-9-9
from oslo.config import cfg
from nova import db
from nova.scheduler import filters
class IsolatedscheduleFilter(filters.BaseHostFilter):
"""Keep specified instances to selected zone or aggregate or host."""
# we can make allHosts with a static variable,
# with this way it doesn't need get data every time.
#此函数将会在每次调度过滤判断自动调用,更多参考 nova-scheduler详解 openstack-ice版
def host_passes(self, host_state, filter_properties):
context = filter_properties['context'].elevated()
#从数据库获取
当前租户
所有可以使用的zones
scheduler_zone_infos = db.scheduler_info_get_by_tenant_id(context, context.project_id, type="zone")
zone_hosts = []
#根据可用的zones迭代获取隶属于该zones下面所有的hosts
for info in scheduler_zone_infos:
ag_list = db.hosts_get_by_zone(context, info.isolated_id, key='availability_zone')
for ag in ag_list:
zone_hosts = zone_hosts + ag.hosts
#从数据库获取
当前租户
所有可以使用的aggregates
scheduler_aggregate_infos = db.scheduler_info_get_by_tenant_id(context, context.project_id, type="aggregate")
aggregate_hosts = []
#根据可用的
aggregates
迭代获取隶属于该
aggregates
下面所有的hosts
for info in scheduler_aggregate_infos:
hosts = db.aggregate_host_get_all(context, info.isolated_id)
aggregate_hosts = aggregate_hosts + hosts
#从数据库获取当前租户所有可以使用的hosts
scheduler_host_infos = db.scheduler_info_get_by_tenant_id(context, context.project_id, type="host")
just_hosts = []
for info in scheduler_host_infos:
just_hosts.append(info.isolated_name)
#将所有可以的zones下面的hosts和aggregates下面的hosts以及可用的hosts合并,即为该租户所有可用的hosts
allHosts = list(set(zone_hosts + aggregate_hosts + just_hosts))
#if host in allHosts or allHosts is empty return True
#如果当前host在上述
allHosts
,则返回true,上层将会yield加入到可用hosts集合中
#关于yield用法参考博文: Python yield语法 使用实战详解
if host_state.host in allHosts or len(allHosts) == 0: #如果数据库没有任何信息,即初始状态则所有hosts都可用
return True
return False
# this function not use now
def get_enabled_hosts(self, hosts, filter_properties):
pass
|