Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
5d68b07
manage: Support Ironic in sync_aggregates
joker-at-work Feb 24, 2021
3d28480
metrics: Measure orphaned resource allocations
grandchild Aug 31, 2023
8727478
Support in-cluster (anti-)affinity for VMware
joker-at-work Dec 2, 2024
8b0a6ef
vmware: Restructure vm- and host-group functions in cluster_util
joker-at-work Aug 27, 2021
4ad5ad3
vmware: Refactor VM rule creation in cluster_util
joker-at-work Aug 27, 2021
7c93acc
vmware: Add function to retrieve all DRS groups of a cluster
joker-at-work Jul 15, 2021
5d00466
vmware: Add function to retrieve all DRS rules of a cluster
joker-at-work Jul 26, 2021
831f973
vmware: Set _compute_host on VMwareVMOps
joker-at-work Sep 17, 2021
212d54b
vmware: Use a prefix in DRS groups and rules
joker-at-work Jul 15, 2021
30348b1
vmware: Remove no longer used "fetch_cluster_properties()"
joker-at-work Sep 16, 2021
f92090d
vmware: Add helper to set DRS overrides
joker-at-work Jan 28, 2025
0b76db8
vmware: Don't add VmGroups for server-groups
joker-at-work Sep 16, 2021
4fbd161
vmware: Remove cleaning of empty DRS groups
joker-at-work Sep 16, 2021
42a7160
vmware: Add DRS rule lifecycle helpers
joker-at-work Sep 16, 2021
1097c93
vmware: Implement sync_server_group()
joker-at-work Sep 16, 2021
4530a51
objects: Add get_by_instance_uuids() to InstanceGroupList
joker-at-work Jul 9, 2021
154cddf
Add a way to trigger a server-group sync on the driver
joker-at-work Sep 16, 2021
c1f8258
Add public method to remove members from InstanceGroup
joker-at-work Jun 17, 2021
c80477d
vmware: Add a DRS rule sync-loop
joker-at-work Sep 16, 2021
a3d9188
vmware: Use sync_server_group() in VM lifecycle
joker-at-work Sep 16, 2021
b30f1c8
api: Pre-query not deleted members in server groups
joker-at-work Aug 24, 2021
f40525e
api: server_group's _get_not_deleted returns hosts
joker-at-work Jun 17, 2021
db0d2a5
api: Add an update method for server-groups
joker-at-work Jun 17, 2021
732bbc4
Enhance performance of get instance groups from DB
bashar-alkhateeb Jan 23, 2023
3a2c876
api: Send server-group update to relevant hosts
joker-at-work Sep 27, 2021
f8fa192
Add option to reserve all memory
joker-at-work Mar 28, 2019
d20849f
Add custom scheduler, memory reservation and DRS overrides for big VMs.
joker-at-work Jul 24, 2019
419ede6
[vmware] Remove/Add big VM settings on resize
joker-at-work Mar 26, 2020
34700da
Add function to check for special spawning needs
joker-at-work Oct 28, 2019
96d302c
Vmware: Refactor update_cluster_placement
fwiesel Sep 27, 2021
b64c26f
objects: Refactor Migration filtering
fwiesel Sep 27, 2021
8e86696
vmware: Sync server-group during migration
fwiesel Sep 27, 2021
ab81aa0
Vmware: Add option to remove vm from vm-group
fwiesel Oct 4, 2021
566865f
vmware: Enable disabled DRS rules in sync
joker-at-work May 10, 2022
166f24a
vmware: Pass VCState into VMwareVMOps
joker-at-work Nov 18, 2022
1e6e106
vmware: soft-anti-affinity can use multiple DRS rules
joker-at-work Nov 18, 2022
5e60f95
vmware: Delete duplicate DRS rules
joker-at-work Aug 3, 2023
d4ced4e
[vmware] Allow root-disk > flavor.root_gb for BFV
Scsabiii Sep 6, 2019
d5e15c5
[vmware] Don't rely on empty image_ref for BFV detection
joker-at-work Oct 16, 2019
277dba0
[vmware] allow to relocate a VM to another cluster while resizing
leust Nov 20, 2019
f0737eb
vmware: Use right adapter-type for resize volume attach
joker-at-work Jun 25, 2020
0f448c4
vmware: Support memoryAllocation change on resize
joker-at-work Jul 22, 2020
360964c
VmWare: Create ServiceLocatorSpec
fwiesel Aug 5, 2021
6da13e3
Vmware: Live-Migration of VMs
fwiesel Oct 2, 2021
850d448
vmware: Clear MOref cache on source after migration
grandchild Jan 5, 2024
8594130
Vmwareapi: Live-migration changes on conductor level.
fwiesel Oct 4, 2021
d6add34
Add `_create_host_group_spec()` to cluster_util
joker-at-work Nov 8, 2019
88e17ab
[vmwareapi] Fix resizing of images
mmidolesov Apr 5, 2018
f13b01c
Vmware: Use a more generic serialisation of specs to json
fwiesel Feb 8, 2022
350a383
Expose volume sizes to scheduler during resize/migration
joker-at-work Oct 24, 2023
c847081
vmware: Add option for setting default hw_version
joker-at-work Dec 7, 2020
a0eaffe
flatten power_sync_state to intervall duration
notandy Jan 4, 2019
fd5c30f
Remove @safe_connect from _get_provider_aggregates
mmidolesov Nov 22, 2019
76a7902
[vmware] Don't rely on defined image's hw_vif_model
joker-at-work Mar 24, 2020
493607c
vmware: Let destroy_vm() re-raise InvalidArgument fault
joker-at-work Aug 31, 2020
d5cf9b1
vmware: Switch default VIF model
joker-at-work Sep 9, 2020
31af3f0
vmware: Optionally attach disconnected serial ports
joker-at-work Feb 11, 2021
ebd0a5c
VMware: Fix empty vim.get_properties_for_..._objects
grandchild Feb 24, 2021
3506d49
vmware: Add constants for DRS-created vCLS VMs
joker-at-work Apr 21, 2021
ebb0cf3
Do not block on reservation while attaching
fwiesel Apr 16, 2018
d8a79ae
Don't call detach without attachment_id and other attachments
joker-at-work Jan 7, 2021
11783de
Vmwareapi: Use oslo_vmware get_object_property instead of nova one
fwiesel Feb 7, 2022
5e0417b
scheduler: Add method for retrieving all traits
joker-at-work Aug 7, 2023
a1621b1
Idempotent binding creation
fwiesel Jun 22, 2021
6bf9612
vmware: Add get_datastore_ref_by_name helper
joker-at-work Nov 16, 2022
3feab43
Add more password generation options
fwiesel Nov 25, 2022
209683f
Vmware: Handle deleted image graceful
fwiesel Oct 4, 2021
32c2f62
vmware: Use moref value for logging cluster_ref
joker-at-work Oct 15, 2021
6441b17
vmware: Attach root disk first
joker-at-work Jun 7, 2022
5030247
vmwareapi: disk backing uuid is optional
mmidolesov Apr 4, 2018
aac0870
Vmware: Handle missing propSet in list_vms
fwiesel Oct 4, 2021
cb14339
vmware: Detect automatically disabled host on restart
joker-at-work Jul 13, 2020
c5856e7
vmware: Add history collectors for Task and Event
imitevm Oct 30, 2019
2d186f2
Merge clone vm and glance parallel image import
mmidolesov Mar 28, 2018
f3a6d5e
VMware: Image as VM template
joker-at-work Dec 13, 2024
65f813f
Vmwareapi: Fix some linting issues
fwiesel Aug 26, 2021
57b1006
vmwareapi: Switch to using olso_vmware.vim_util
fwiesel Aug 26, 2021
23a95cc
vmwareapi: Handle duplicate name in OVA import
imitevm Jan 29, 2019
bfeda53
Vmware: Use Rpc instead of own session
fwiesel Feb 10, 2022
ff76e9b
[vmware] don't report empty inventory (fixed keyerror)
notandy Dec 18, 2018
763e0d7
[vmware] Add configurable reservations per hostgroup
joker-at-work Sep 27, 2019
2eb51bb
[vmware] Optionally spawn VMs on prepared empty host
joker-at-work Oct 28, 2019
44fd619
vmware: Switch from memoryReservationLockedToMax to memoryAllocation
joker-at-work Jul 22, 2020
39d1da9
[memreserv] Reserve memory for certain flavors
grandchild Oct 27, 2020
7e4641f
vmware: `_list_instances_in_cluster()` returns properties
joker-at-work Nov 8, 2019
b299651
vmware: Add helper to fetch DRS overrides
joker-at-work Nov 22, 2021
d7f5be3
Support spawning big VMs
joker-at-work Nov 8, 2019
955bb11
Vmware: Use WithRetrieval to get all results
fwiesel Aug 11, 2021
51f6b59
Vmwareapi: Split out getting hosts from get_stats_from_cluster
fwiesel Aug 12, 2021
81fddbc
VmWare: Refactored resource and inventory collection
fwiesel Aug 26, 2021
7ea149e
ResourceTracker: Fetch Bdms up front
fwiesel Oct 4, 2021
ed5da0f
Vmware: Aggregate cpu_info on item level
fwiesel Jan 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions nova/api/openstack/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,16 @@ def get_limit_and_marker(request):
return limit, marker


def get_limit_and_offset(request):
"""Get limit and offset parameters from request."""
params = get_pagination_params(request)
limit = CONF.api.max_limit
limit = min(limit, params.get('limit', limit))
offset = params.get('offset', None)

return limit, offset


def get_id_from_href(href):
"""Return the id or uuid portion of a url.

Expand Down
1 change: 1 addition & 0 deletions nova/api/openstack/compute/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ def _create_controller(main_controller, action_controller_list):
}),
('/os-server-groups/{id}', {
'GET': [server_groups_controller, 'show'],
'PUT': [server_groups_controller, 'update'],
'DELETE': [server_groups_controller, 'delete']
}),
('/os-services', {
Expand Down
15 changes: 15 additions & 0 deletions nova/api/openstack/compute/schemas/server_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,18 @@
'properties': {},
'additionalProperties': True,
}

update = {
'type': 'object',
'properties': {
'add_members': {
'type': 'array',
'items': parameter_types.server_id,
},
'remove_members': {
'type': 'array',
'items': parameter_types.server_id,
}
},
'additionalProperties': False
}
197 changes: 183 additions & 14 deletions nova/api/openstack/compute/server_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"""The Server Group API Extension."""

import collections
import itertools

from oslo_log import log as logging
import webob
Expand All @@ -26,6 +27,7 @@
from nova.api.openstack.compute.schemas import server_groups as schema
from nova.api.openstack import wsgi
from nova.api import validation
from nova.compute import api as compute
import nova.conf
from nova import context as nova_context
import nova.exception
Expand All @@ -40,20 +42,29 @@
CONF = nova.conf.CONF


def _get_not_deleted(context, uuids):
GROUP_POLICY_OBJ_MICROVERSION = "2.64"


def _get_not_deleted(context, uuids, not_deleted_inst=None):
if not_deleted_inst:
# short-cut if we already pre-built a list of not deleted instances to
# be more efficient
return {u: not_deleted_inst[u] for u in uuids
if u in not_deleted_inst}

mappings = objects.InstanceMappingList.get_by_instance_uuids(
context, uuids)
inst_by_cell = collections.defaultdict(list)
cell_mappings = {}
found_inst_uuids = []
found_inst = {}

# Get a master list of cell mappings, and a list of instance
# uuids organized by cell
for im in mappings:
if not im.cell_mapping:
# Not scheduled yet, so just throw it in the final list
# and move on
found_inst_uuids.append(im.instance_uuid)
found_inst[im.instance_uuid] = None
continue
if im.cell_mapping.uuid not in cell_mappings:
cell_mappings[im.cell_mapping.uuid] = im.cell_mapping
Expand All @@ -67,11 +78,11 @@ def _get_not_deleted(context, uuids):
{'cell': cell_mapping.identity, 'num': len(inst_uuids)})
filters = {'uuid': inst_uuids, 'deleted': False}
with nova_context.target_cell(context, cell_mapping) as ctx:
found_inst_uuids.extend([
inst.uuid for inst in objects.InstanceList.get_by_filters(
ctx, filters=filters)])
instances = objects.InstanceList.get_by_filters(
ctx, filters=filters)
found_inst.update({inst.uuid: inst.host for inst in instances})

return found_inst_uuids
return found_inst


def _should_enable_custom_max_server_rules(context, rules):
Expand All @@ -86,7 +97,20 @@ def _should_enable_custom_max_server_rules(context, rules):
class ServerGroupController(wsgi.Controller):
"""The Server group API controller for the OpenStack API."""

def _format_server_group(self, context, group, req):
def __init__(self, **kwargs):
super(ServerGroupController, self).__init__(**kwargs)
self.compute_api = compute.API()

def _format_server_group(self, context, group, req,
not_deleted_inst=None):
"""Format ServerGroup according to API version.

Displays only not-deleted members.

:param:not_deleted_inst: Pre-built dict of instance-uuid: host for
multiple server-groups that are found to be
not deleted.
"""
# the id field has its value as the uuid of the server group
# There is no 'uuid' key in server_group seen by clients.
# In addition, clients see policies as a ["policy-name"] list;
Expand All @@ -105,7 +129,8 @@ def _format_server_group(self, context, group, req):
members = []
if group.members:
# Display the instances that are not deleted.
members = _get_not_deleted(context, group.members)
members = list(_get_not_deleted(context, group.members,
not_deleted_inst))
server_group['members'] = members
# Add project id information to the response data for
# API version v2.13
Expand Down Expand Up @@ -149,6 +174,7 @@ def delete(self, req, id):
def index(self, req):
"""Returns a list of server groups."""
context = req.environ['nova.context']
limit, offset = common.get_limit_and_offset(req)
project_id = context.project_id
# NOTE(gmann): Using context's project_id as target here so
# that when we remove the default target from policy class,
Expand All @@ -166,13 +192,19 @@ def index(self, req):
# Until then, let's keep the old behaviour.
context.can(sg_policies.POLICY_ROOT % 'index:all_projects',
target={'project_id': project_id})
sgs = objects.InstanceGroupList.get_all(context)
sgs = objects.InstanceGroupList.get_all(context,
limit=limit,
offset=offset)
else:
sgs = objects.InstanceGroupList.get_by_project_id(
context, project_id)
limited_list = common.limited(sgs.objects, req)
result = [self._format_server_group(context, group, req)
for group in limited_list]
context, project_id, limit=limit, offset=offset)

members = list(itertools.chain.from_iterable(sg.members
for sg in sgs
if sg.members))
not_deleted = _get_not_deleted(context, members)
result = [self._format_server_group(context, group, req, not_deleted)
for group in sgs]
return {'server_groups': result}

@wsgi.Controller.api_version("2.1")
Expand Down Expand Up @@ -248,3 +280,140 @@ def create(self, req, body):
raise exc.HTTPForbidden(explanation=msg)

return {'server_group': self._format_server_group(context, sg, req)}

@wsgi.Controller.api_version("2.64")
@validation.schema(schema.update)
@wsgi.expected_errors((400, 404))
def update(self, req, id, body):
"""Update a server-group's members

Striving for idempotency, we accept already removed or already
contained members.

We always remove first and then check if we can add the requested
members. That way, removing an instance for a host and adding another
one works in one request.

We do all requested changes or no change.
"""
context = req.environ['nova.context']
project_id = context.project_id
context.can(sg_policies.POLICY_ROOT % 'update',
target={'project_id': project_id})
try:
sg = objects.InstanceGroup.get_by_uuid(context, id)
except nova.exception.InstanceGroupNotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.format_message())

members_to_remove = set(body.get('remove_members', []))
members_to_add = set(body.get('add_members', []))
LOG.info('Called update for server-group %s with add_members: %s and '
'remove_members %s',
id, ', '.join(members_to_add), ', '.join(members_to_remove))

overlap = members_to_remove & members_to_add
if overlap:
msg = ('Parameters "add_members" and "remove_members" are '
'overlapping in {}'.format(', '.join(overlap)))
raise exc.HTTPBadRequest(explanation=msg)

if not members_to_remove and not members_to_add:
LOG.info("No update requested.")
formatted_sg = self._format_server_group(context, sg, req)
return {'server_group': formatted_sg}

# don't do work if it's not necessary. we might be able to get a fast
# way out if this request is already fulfilled
members_to_remove = members_to_remove & set(sg.members)
members_to_add = members_to_add - set(sg.members)

if not members_to_remove and not members_to_add:
LOG.info("State already satisfied.")
formatted_sg = self._format_server_group(context, sg, req)
return {'server_group': formatted_sg}

# retrieve all the instances to add, failing if one doesn't exist,
# because we need to check the hosts against the policy and adding
# non-existent instances doesn't make sense
members_to_search = members_to_add | members_to_remove
found_instances_hosts = _get_not_deleted(context, members_to_search)
missing_uuids = members_to_add - set(found_instances_hosts)
if missing_uuids:
msg = ("One or more members in add_members cannot be found: {}"
.format(', '.join(missing_uuids)))
raise exc.HTTPBadRequest(explanation=msg)

# check if (some of) the VMs are already members of another
# instance_group. We cannot support this as they might contradict.
found_server_groups = \
objects.InstanceGroupList.get_by_instance_uuids(context,
members_to_add)
other_server_groups = [_x.uuid for _x in found_server_groups
if _x.uuid != id]
if other_server_groups:
msg = ("One or more members in add_members is already assigned "
"to another server group. Server groups: {}"
.format(', '.join(other_server_groups)))
raise exc.HTTPBadRequest(explanation=msg)

# check if the policy is still valid with these changes
if sg.policy in ('affinity', 'anti-affinity'):
current_members_hosts = _get_not_deleted(context, sg.members)
current_hosts = set(h for u, h in current_members_hosts.items()
if u not in members_to_remove)
if sg.policy == 'affinity':
outliers = [u for u, h in found_instances_hosts.items()
if h and h not in current_hosts]
elif sg.policy == 'anti-affinity':
outliers = [u for u, h in found_instances_hosts.items()
if h and h in current_hosts]
else:
outliers = None
LOG.warning('server-group update check not implemented for '
'policy %s', sg.policy)
if outliers:
LOG.info('Update of server-group %s with policy %s aborted: '
'policy violation by %s',
id, sg.policy, ', '.join(outliers))
msg = ("Adding instance(s) {} would violate policy '{}'."
.format(', '.join(outliers), sg.policy))
raise exc.HTTPBadRequest(explanation=msg)

# update the server group and save it
if members_to_remove:
objects.InstanceGroup.remove_members(context, sg.id,
members_to_remove, sg.uuid)
if members_to_add:
try:
objects.InstanceGroup.add_members(context, id, members_to_add)
except Exception:
LOG.exception('Failed to add members.')
if members_to_remove:
LOG.info('Trying to add removed members again after '
'error.')
objects.InstanceGroup.add_members(context, id,
members_to_remove)
raise

LOG.info("Changed server-group %s in DB.", id)

# refresh InstanceGroup object, because we changed it directly in the
# DB.
sg.refresh()

# update the request-specs of the updated members
for member_uuid in found_instances_hosts:
request_spec = \
objects.RequestSpec.get_by_instance_uuid(context, member_uuid)
if member_uuid in members_to_add:
request_spec.instance_group = sg
else:
request_spec.instance_group = None
request_spec.save()

# tell the compute hosts about the update, so they can sync if
# necessary
hosts_to_update = set(h for h in found_instances_hosts.values() if h)
self.compute_api.sync_server_group(context, hosts_to_update, id)

return {'server_group': self._format_server_group(context, sg, req)}
Empty file added nova/bigvm/__init__.py
Empty file.
Loading