U
    dfC                     @   s   d Z ddlmZ ddlmZmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ zdd	lZdd
lmZ W n ek
r   d	 ZZY nX dZeddZeeZG dd deZd	S )z"AWS DynamoDB result store backend.    )
namedtuple)sleeptime)
_parse_url)ImproperlyConfigured)
get_logger   )KeyValueStoreBackendN)ClientError)DynamoDBBackendDynamoDBAttributename	data_typec                       s  e Zd ZdZdZdZdZdZdZdZ	dZ
edddZed	d
dZedddZedddZdZd3 fdd	Zd4ddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zd5d!d"Zd#d$ Zd%d& Zd'd( Zed)d* Zd+d, Z d-d. Z!d/d0 Z"d1d2 Z#  Z$S )6r   zAWS DynamoDB result backend.

    Raises:
        celery.exceptions.ImproperlyConfigured:
            if module :pypi:`boto3` is not available.
    Zceleryr   NTidSr   resultB	timestampNttlc              
      s  t  j|| || _|p| j| _ts,tdd}d }d }|d k	rdt|\}}	}
}}}}|}|}|d k	}|d k	}||krtd|}|	dkrd|
 | _d| _t	
d| j n|	| _| jjj}|d}|r|| _t|d	| j| _t|d
| j| _|d| j}|rVzt|| _W n6 tk
rT } zt	jd|d |W 5 d }~X Y nX |p`| j| _| j| j| jf| _d | _|r| j||d d S )NzBYou need to install the boto3 library to use the DynamoDB backend.Fz6You need to specify both the Access Key ID and Secret.	localhostzhttp://localhost:z	us-east-1z*Using local-only DynamoDB endpoint URL: {}Zdynamodb_endpoint_urlreadwriteZttl_secondsz!TTL must be a number; got "{ttl}")exc_info)access_key_idsecret_access_key)super__init__url
table_nameboto3r   	parse_urlendpoint_url
aws_regionloggerwarningformatZappconfgetintread_capacity_unitswrite_capacity_unitstime_to_live_seconds
ValueErrorerror
_key_field_value_field_timestamp_field_available_fields_client_get_client)selfr   r    argskwargsZaws_credentials_givenaws_access_key_idaws_secret_access_keyschemeZregionportusernamepasswordtablequeryZaccess_key_givenZsecret_key_given_getZconfig_endpoint_urlr   e	__class__ </tmp/pip-unpacked-wheel-9cz4377o/celery/backends/dynamodb.pyr   >   s    

zDynamoDBBackend.__init__c                 C   sx   | j dkrrd| ji}|dk	r,|||d | jdk	r@| j|d< tjd|| _ |   |  dk	rr|   | 	  | j S )zGet client connection.NZregion_name)r9   r:   r#   dynamodb)rG   )
r4   r$   updater#   r!   client_get_or_create_table_has_ttl_validate_ttl_methods_set_table_ttl)r6   r   r   Zclient_parametersrE   rE   rF   r5      s*    
 

 zDynamoDBBackend._get_clientc                 C   s6   | j j| j jdg| j| j jddg| j| jddS )z=Get the boto3 structure describing the DynamoDB table schema.)AttributeNameZAttributeTypeHASH)rN   ZKeyType)ZReadCapacityUnitsZWriteCapacityUnits)ZAttributeDefinitions	TableNameZ	KeySchemaZProvisionedThroughput)r0   r   r   r    r+   r,   r6   rE   rE   rF   _get_table_schema   s    z!DynamoDBBackend._get_table_schemac              
   C   s   |   }zB| jjf |}td| j | d td| j |W S  tk
r } z:|j	d 
dd}|dkr| jj| jd W Y 
S |W 5 d	}~X Y nX d	S )
z=Create table if not exists, otherwise return the description.z*DynamoDB Table {} did not exist, creating.ACTIVEz#DynamoDB Table {} is now available.ErrorCodeUnknownZResourceInUseExceptionrP   N)rR   r4   Zcreate_tabler%   infor'   r    _wait_for_table_statusr
   responser)   describe_table)r6   Ztable_schematable_descriptionrB   
error_coderE   rE   rF   rJ      s,    
z$DynamoDBBackend._get_or_create_tablec                 C   s   | j dkrdS | j dkS )zReturn the desired Time to Live config.

        - True:  Enable TTL on the table; use expiry.
        - False: Disable TTL on the table; don't use expiry.
        - None:  Ignore TTL on the table; don't use expiry.
        Nr   )r-   rQ   rE   rE   rF   rK      s    zDynamoDBBackend._has_ttlc                 C   sb   d}g }t |D ]}t| j|s|| q|r^tdjd|d tdjd|ddS )z:Verify boto support for the DynamoDB Time to Live methods.)update_time_to_livedescribe_time_to_livezdboto3 method(s) {methods} not found; ensure that boto3>=1.9.178 and botocore>=1.12.178 are installed,)methodsz#boto3 method(s) {methods} not foundN)	listhasattrr4   appendr%   r/   r'   joinAttributeError)r6   Zrequired_methodsZmissing_methodsmethodrE   rE   rF   rL      s"    z%DynamoDBBackend._validate_ttl_methodsc                 C   s   | j |  |ddS )zBGet the boto3 structure describing the DynamoDB TTL specification.)ZEnabledrN   )rP   ZTimeToLiveSpecification)r    rK   )r6   ttl_attr_namerE   rE   rF   _get_ttl_specification  s
    z&DynamoDBBackend._get_ttl_specificationc              
   C   s|   z| j j| jd}W nb tk
rv } zD|jd dd}|jd dd}tdj| j||d |W 5 d }~X Y nX |S )NrW   rT   rU   rV   MessagezJError describing Time to Live on DynamoDB table {table}: {code}: {message})r?   codemessage)	r4   r_   r    r
   rZ   r)   r%   r/   r'   )r6   descriptionrB   r]   error_messagerE   rE   rF   _get_table_ttl_description  s     
z*DynamoDBBackend._get_table_ttl_descriptionc           	      C   s|  |   }|d d }|dkrd|d d }|  r|| jjkrtdj|dkrPdnd| jd	 |S nN|d
kr|  stdj|dkrdnd| jd	 |S ntdj|| jd |dkr|n| jj}z<| j	j
f | j|d}tdj| j|  | jjd |W S  tk
rv } zT|jd dd}|jd dd}tdj|  rPdnd| j||d |W 5 d}~X Y nX dS )z,Enable or disable Time to Live on the table.ZTimeToLiveDescriptionZTimeToLiveStatus)ENABLEDZENABLINGrN   z5DynamoDB Time to Live is {situation} on table {table}rp   zalready enabledzcurrently being enabled)Z	situationr?   )DISABLEDZ	DISABLINGrq   zalready disabledzcurrently being disabledzWUnknown DynamoDB Time to Live status {status} on table {table}. Attempting to continue.)statusr?   )rh   zUDynamoDB table Time to Live updated: table={table} enabled={enabled} attribute={attr})r?   ZenabledattrrT   rU   rV   rj   zHError {action} Time to Live on DynamoDB table {table}: {code}: {message}ZenablingZ	disabling)actionr?   rk   rl   N)ro   rK   
_ttl_fieldr   r%   debugr'   r    r&   r4   r^   ri   rX   r
   rZ   r)   r/   )	r6   rm   rr   Zcur_attr_name	attr_namespecificationrB   r]   rn   rE   rE   rF   rM   +  s|    
		&
	zDynamoDBBackend._set_table_ttlrS   c                 C   sN   d}|sJ| j j| jd}td| j| |d d }||k}td qdS )z#Poll for the expected table status.FrW   z+Waiting for DynamoDB table {} to become {}.ZTableZTableStatusr   N)rI   r[   r    r%   rv   r'   r   )r6   expectedZachieved_stater\   Zcurrent_statusrE   rE   rF   rY     s    z&DynamoDBBackend._wait_for_table_statusc                 C   s   | j | jj| jj|iidS )z0Construct the item retrieval request parameters.)rP   ZKey)r    r0   r   r   )r6   keyrE   rE   rF   _prepare_get_request  s     z$DynamoDBBackend._prepare_get_requestc              	   C   s~   t  }| j| jj| jj|i| jj| jj|i| jj| jjt|iid}|  rz|d 	| j
j| j
jtt|| j ii |S )z/Construct the item creation request parameters.)rP   Itemr|   )r   r    r0   r   r   r1   r2   strrK   rH   ru   r*   r-   )r6   rz   valuer   Zput_requestrE   rE   rF   _prepare_put_request  s0       z$DynamoDBBackend._prepare_put_requestc                    s    d kri S  fdd| j D S )z1Convert get_item() response to field-value pairs.r|   c                    s$   i | ]}|j  d  |j  |j qS )r|   r   ).0fieldraw_responserE   rF   
<dictcomp>  s    z1DynamoDBBackend._item_to_dict.<locals>.<dictcomp>)r3   )r6   r   rE   r   rF   _item_to_dict  s
    
zDynamoDBBackend._item_to_dictc                 C   s   |   S N)r5   rQ   rE   rE   rF   rI     s    zDynamoDBBackend.clientc                 C   s8   t |}| |}| jjf |}| |}|| jjS r   )r}   r{   rI   Zget_itemr   r)   r1   r   )r6   rz   request_parametersZitem_responseitemrE   rE   rF   r)     s
    

zDynamoDBBackend.getc                 C   s&   t |}| ||}| jjf | d S r   )r}   r   rI   Zput_item)r6   rz   r~   r   rE   rE   rF   set  s    zDynamoDBBackend.setc                    s    fdd|D S )Nc                    s   g | ]}  |qS rE   )r)   )r   rz   rQ   rE   rF   
<listcomp>  s     z(DynamoDBBackend.mget.<locals>.<listcomp>rE   )r6   keysrE   rQ   rF   mget  s    zDynamoDBBackend.mgetc                 C   s$   t |}| |}| jjf | d S r   )r}   r{   rI   Zdelete_item)r6   rz   r   rE   rE   rF   delete  s    
zDynamoDBBackend.delete)NN)NN)rS   )%__name__
__module____qualname____doc__r    r+   r,   r$   r#   r-   Zsupports_autoexpirer   r0   r1   r2   ru   r3   r   r5   rR   rJ   rK   rL   ri   ro   rM   rY   r{   r   r   propertyrI   r)   r   r   r   __classcell__rE   rE   rC   rF   r      s@   Y


p
	
r   )r   collectionsr   r   r   Zkombu.utils.urlr   r"   Zcelery.exceptionsr   Zcelery.utils.logr   baser	   r!   Zbotocore.exceptionsr
   ImportError__all__r   r   r%   r   rE   rE   rE   rF   <module>   s   
