'Write new metadata to the database.
The caller may optionally provide a merge_metadata() function, which
takes two arguments - the metadata passed to metadata_set() and the
current metadata of the resource - and returns the merged metadata to
write. If merge_metadata is not provided, the metadata passed to
metadata_set() is written verbatim, overwriting any existing metadata.
If a race condition is detected, the write will be retried with the new
result of merge_metadata() (if it is supplied) or the verbatim data (if
it is not).'

@resource_objects.retry_on_conflict
def metadata_set(self, metadata, merge_metadata=None):

    if ((self.id is None) or (self.action == self.INIT)):
        raise exception.ResourceNotAvailable(resource_name=self.name)
    refresh = (merge_metadata is not None)
    db_res = resource_objects.Resource.get_obj(self.stack.context, self.id, refresh=refresh, fields=('name', 'rsrc_metadata', 'atomic_key', 'engine_id', 'action', 'status'))
    if (db_res.action == self.DELETE):
        self._db_res_is_deleted = True
        LOG.debug('resource    %(name)s,    id:    %(id)s    is    DELETE_%(st)s,    not    setting    metadata', {'name': self.name, 'id': self.id, 'st': db_res.status})
        raise exception.ResourceNotAvailable(resource_name=self.name)
    LOG.debug('Setting    metadata    for    %s', six.text_type(self))
    if refresh:
        metadata = merge_metadata(metadata, db_res.rsrc_metadata)
    if db_res.update_metadata(metadata):
        self._incr_atomic_key(db_res.atomic_key)
    self._rsrc_metadata = metadata
