def start(self, asset, conflict=False): # Fetch metadata with a fresh etag try: old_metadata = Payload(self.client.GET(asset.describedby_link)) # If no metadata is found, we cannot do any metadata mapping except HTTPClientError as e: logging.error(u'Asset Metadata fetching failed %s', str(e)) return # If there was an internal server error (5xx), wait and retry except HTTPServerError as e: logging.error(u'Asset Metadata fetching failed %s', str(e)) logging.warn(u'Retrying in 10 seconds...') time.sleep(10) raise Retry # Copy metadata and operate on the copy, so we can compare them later new_metadata = Payload(old_metadata.generate()) scope = { 'asset': asset, 'metadata': new_metadata, } for field, expr in self.mappings.items(): logging.info('%s = %s', field, expr) new_metadata.set(field, eval(expr, scope)) logging.log(u'Resulting payload', new_metadata.generate(), 'xml') # Only update if we produced any differences, else we will have a circle of updates if new_metadata != old_metadata: logging.info(u'Updating metadata...') self.client.PUT( asset.describedby_link, new_metadata, etag=old_metadata.response_etag ) logging.info(u'Updated metadata.') else: logging.info(u'No changes to metadata.')
def start(self, asset, conflict=False): # Fetch metadata with a fresh etag try: old_metadata = Payload(self.client.GET(asset.describedby_link)) # If no metadata is found, we cannot do any metadata mapping except HTTPClientError as e: logging.error(u'Asset Metadata fetching failed %s', str(e)) return # If there was an internal server error (5xx), wait and retry except HTTPServerError as e: logging.error(u'Asset Metadata fetching failed %s', str(e)) logging.warn(u'Retrying in 10 seconds...') time.sleep(10) raise Retry # Copy metadata and operate on the copy, so we can compare them later new_metadata = Payload(old_metadata.generate()) scope = { 'asset': asset, 'metadata': new_metadata, } for field, expr in self.mappings.items(): logging.info('%s = %s', field, expr) new_metadata.set(field, eval(expr, scope)) logging.log(u'Resulting payload', new_metadata.generate(), 'xml') # Only update if we produced any differences, else we will have a circle of updates if new_metadata != old_metadata: logging.info(u'Updating metadata...') self.client.PUT(asset.describedby_link, new_metadata, etag=old_metadata.response_etag) logging.info(u'Updated metadata.') else: logging.info(u'No changes to metadata.')
def __call__(self, *args, **kwargs): for retry in range(max_retries): try: logging.debug(u'RetryOnConflict, attempt %i of %i...', retry + 1, max_retries) kwargs['conflict'] = retry > 0 return (self.func)(*args, **kwargs) # If we have a conflict, retry the entire operation except HTTPClientError as e: logging.warn(u'Update failed %s', str(e)) if e.response.status_code == 409: # etag violation logging.warn(u'Retrying...') else: break except Retry as e: logging.warn(u'Retrying...')
def create_or_update_asset( id=None, metadata=None, acl=None, mediaacl=None, tags=None, materialtype=None, category=None, rightscode=None, client=None): """ Creates or Updates an Item with a given ``id``. Metadata updates will be retried three times if there are conflicts. Args: id (Optional[unicode]): An asset id or "site identity" metadata (Optional[vizone.vdf.Payload]): The metadata to update to. Can be a dict with a 'form' field too. acl (Optional[vizone.vizone.payload.user_group.Acl]): Specify a ACL when creating the Asset mediaacl (Optional[vizone.vizone.payload.user_group.Acl]): Specify a Media ACL when creating the Asset tags (Optional[dict]): scheme => term dictionary for custom tags when creating the Asset materialtype (Optional[unicode]): Set the Material Type to this when creating the Asset category (Optional[unicode]): Set the Category to this when creating the Asset rightscode (Optional[unicode]): Set the Rights Code to this when creating the Asset client (Optional[vizone.client.Instance]): A Viz One client to use (None means the default) Returns: vizone.payload.asset.Item: The updated or created Asset Entry """ old_payload = None client = client or get_default_instance() # Create or Update Placeholder try: asset = get_asset_by_id(id, headers={'X-Inline': 'describedby'}, client=client) old_payload = asset.describedby_link.metadata except HTTPClientError: try: logging.info(u'Item %s does not exist, creating.', id) asset = Item(id=id) if acl: asset.acl = acl if mediaacl: asset.mediaacl = mediaacl if materialtype: asset.materialtype = materialtype if category: asset.category = category if rightscode: asset.rightscode = rightscode if tags: for scheme, term in sorted(tags.items()): asset.keywords.append( AtomCategory(scheme=scheme, term=term) ) asset = create_asset(asset, client=client) except (HTTPClientError, HTTPServerError): logging.error(u'Could not create asset %s, skipping.', id) return # Create payload if metadata is a dict if type(metadata) is dict: form = metadata.pop('form') if old_payload is None: models = MetadataFormCollection(client.GET(asset.models_link)) model_link = [model.self_link for model in models.entries if model.name == form][0] model = Model(client.GET(model_link)) payload = model.to_payload() else: payload = old_payload for name, value in metadata.items(): payload.set(name, value) else: payload = metadata # Update Metadata if needed if payload is not None and payload != old_payload: logging.info(u'Updating metadata for asset %s.', asset.id) for _ in range(3): try: asset.describedby_link.metadata = Payload(client.PUT(asset.describedby_link, payload)) break except HTTPServerError: logging.error(u'Could not update metadata for asset %s.', asset.id) return except HTTPClientError as e: logging.info(u'Asset Metadata update failed %s', str(e)) if e.responstatus_code == 412: logging.warn(u'Retrying...') asset.parse(client.GET(asset.self_link)) else: break else: logging.info(u'Updating metadata for asset %s not needed.', asset.id) return asset