'Save updates to this instance
Column-wise updates will be made based on the result of
self.what_changed(). If expected_task_state is provided,
it will be checked against the in-database copy of the
instance before updates are made.
:param:context: Security context
:param:expected_task_state: Optional tuple of valid task states
for the instance to be in
:param:expected_vm_state: Optional tuple of valid vm states
for the instance to be in
:param admin_state_reset: True if admin API is forcing setting
of task_state/vm_state'

@base.remotable
def save(self, expected_vm_state=None, expected_task_state=None, admin_state_reset=False):

    self._sync_cells = (not self._cell_name_blocks_sync())
    context = self._context
    cell_type = cells_opts.get_cell_type()
    if (cell_type is not None):
        stale_instance = self.obj_clone()
    cells_update_from_api = ((cell_type == 'api') and self.cell_name and self._sync_cells)
    if cells_update_from_api:
        def _handle_cell_update_from_api():
            cells_api = cells_rpcapi.CellsAPI()
            cells_api.instance_update_from_api(context, stale_instance, expected_vm_state, expected_task_state, admin_state_reset)
    self._extra_values_to_save = {}
    updates = {}
    changes = self.obj_what_changed()
    for field in self.fields:
        if (self.obj_attr_is_set(field) and isinstance(self.fields[field], fields.ObjectField)):
            try:
                getattr(self, ('_save_%s' % field))(context)
            except AttributeError:
                if (field in _INSTANCE_EXTRA_FIELDS):
                    self._save_extra_generic(field)
                    continue
                LOG.exception(_LE('No    save    handler    for    %s'), field, instance=self)
            except db_exc.DBReferenceError as exp:
                if (exp.key != 'instance_uuid'):
                    raise
                raise exception.InstanceNotFound(instance_id=self.uuid)
        elif (field in changes):
            if ((field == 'cell_name') and (self[field] is not None) and self[field].startswith(cells_utils.BLOCK_SYNC_FLAG)):
                updates[field] = self[field].replace(cells_utils.BLOCK_SYNC_FLAG, '', 1)
            else:
                updates[field] = self[field]
    if self._extra_values_to_save:
        db.instance_extra_update_by_uuid(context, self.uuid, self._extra_values_to_save)
    if (not updates):
        if cells_update_from_api:
            _handle_cell_update_from_api()
        return
    if ('cleaned' in updates):
        if updates['cleaned']:
            updates['cleaned'] = 1
        else:
            updates['cleaned'] = 0
    if (expected_task_state is not None):
        updates['expected_task_state'] = expected_task_state
    if (expected_vm_state is not None):
        updates['expected_vm_state'] = expected_vm_state
    expected_attrs = [attr for attr in _INSTANCE_OPTIONAL_JOINED_FIELDS if self.obj_attr_is_set(attr)]
    if ('pci_devices' in expected_attrs):
        expected_attrs.remove('pci_devices')
    if ('system_metadata' not in expected_attrs):
        expected_attrs.append('system_metadata')
        expected_attrs.append('flavor')
    (old_ref, inst_ref) = db.instance_update_and_get_original(context, self.uuid, updates, columns_to_join=_expected_cols(expected_attrs))
    self._from_db_object(context, self, inst_ref, expected_attrs=expected_attrs)
    if cells_update_from_api:
        _handle_cell_update_from_api()
    elif (cell_type == 'compute'):
        if self._sync_cells:
            cells_api = cells_rpcapi.CellsAPI()
            cells_api.instance_update_at_top(context, stale_instance)
    def _notify():
        new_ref = self.obj_clone()
        notifications.send_update(context, old_ref, new_ref)
    if (not self._sync_cells):
        _notify = (lambda : None)
    _notify()
    self.obj_reset_changes()
