o
    iq                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlmZ d dlm	Z	 d dlm
Z
 d dlmZ d dlmZ d dlmZ d dlZd dlZd dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dl m!Z! d dl"m#Z# d dl$m%Z% d dl&m'Z' d dl(m)Z* d dl+m,Z, d dl-m.Z. d dl/m0Z0 d dl1m2Z2 d dl3m4Z4 d dl5m6Z6 ee7Z8e9dZ:dZ;e<d hZ=d!d"d#e>fd$d%Z?G d&d" d"e,Z@e@ Z)G d'd( d(eAZBejCG d)d* d*ZDejCG d+d, d,ZEejCG d-d. d.ZFejCG d/d0 d0ZGejCG d1d2 d2ZHejCG d3d4 d4ZIejCG d5d6 d6ZJejCG d7d8 d8ZKejCG d9d: d:ZLejCG d;d< d<ZMeNeOef ZPeNeOef ZQG d=d> d>ZRdS )?    N)TYPE_CHECKING)Any)Iterable)Mapping)Optional)Sequence)agent)gitmetadata)process_tags)runtime)get_hostname)
get_loggeris_distribution_available)ConfigMetadata)Payload)PayloadType)
RCCallback)PublisherSubscriberConnector)RemoteConfigSubscriber)REMOTE_CONFIG_AGENT_ENDPOINT)ServiceStatus)config)DDConfig)telemetry_writer)TELEMETRY_LOG_LEVEL)parse_tags_str)	StopWatch)_pep440_to_semverz0^(datadog/\d+|employee)/([^/]+)/([^/]+)/([^/]+)$g      ?zdjango-qcRemoteConfigClientConfigreturnc                 C   s"   | j d ur| j S tdd tD S )Nc                 s   s    | ]}t |V  qd S Nr   .0_ r&   X/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/internal/remoteconfig/client.py	<genexpr>8   s    z'derive_skip_shutdown.<locals>.<genexpr>)_skip_shutdownanyREQUIRE_SKIP_SHUTDOWN)r   r&   r&   r'   derive_skip_shutdown4   s
   
r,   c                   @   s@   e Zd ZdZejedddZejee dddZ	e
eeZdS )r    z_dd.remote_configurationlog_payloadsF)defaultskip_shutdownN)__name__
__module____qualname__
__prefix__r   vboolr-   r   r)   dr,   r/   r&   r&   r&   r'   r    <   s
    c                   @   s   e Zd ZdZdS )RemoteConfigErrorzn
    An error occurred during the configuration update procedure.
    The error is reported to the agent.
    N)r0   r1   r2   __doc__r&   r&   r&   r'   r7   H   s    r7   c                   @      e Zd ZU eed< eed< dS )	SignaturekeyidsigNr0   r1   r2   str__annotations__r&   r&   r&   r'   r:   O      
 r:   c                   @   s2   e Zd ZU eed< ee ed< eed< eed< dS )Keykeytypekeyid_hash_algorithmskeyvalschemeN)r0   r1   r2   r>   r?   listr   r&   r&   r&   r'   rA   U   s
   
 rA   c                   @   s"   e Zd ZU ee ed< eed< dS )Rolekeyids	thresholdN)r0   r1   r2   rF   r>   r?   intr&   r&   r&   r'   rG   ]   s   
 rG   c                   @   sb   e Zd ZU eed< eed< eed< eed< eeef ed< eeef ed< dZ	e
ed< d	d
 ZdS )Root_typespec_versionconsistent_snapshotexpireskeysrolesr   versionc                 C   sz   | j dkr	td| j D ]\}}t|tr!tdi || j|< q| j D ]\}}t|tr:tdi || j|< q'd S )NrootzRoot: invalid root typer&   )	rL   
ValueErrorrP   items
isinstancedictrA   rQ   rG   selfkr4   r&   r&   r'   __post_init__m   s   


zRoot.__post_init__N)r0   r1   r2   r>   r?   r5   r   rA   rG   rR   rJ   r[   r&   r&   r&   r'   rK   c   s   
 rK   c                   @   s*   e Zd ZU ee ed< eed< dd ZdS )
SignedRoot
signaturessignedc                 C   d   t t| jD ]}t| j| trtdi | j| | j|< qt| jtr0tdi | j| _d S d S Nr&   )rangelenr]   rV   rW   r:   r^   rK   rY   ir&   r&   r'   r[   }      zSignedRoot.__post_init__N)r0   r1   r2   rF   r:   r?   rK   r[   r&   r&   r&   r'   r\   x   s   
 r\   c                   @   s6   e Zd ZU eed< eeef ed< eeef ed< dS )
TargetDesclengthhashescustomN)r0   r1   r2   rJ   r?   r   r>   r   r&   r&   r&   r'   rf      s   
 rf   c                   @   sZ   e Zd ZU eed< eeef ed< eed< eed< eeef ed< dZe	ed< dd	 Z
d
S )TargetsrL   ri   rO   rM   targetsr   rR   c                 C   sZ   | j dkr	td| jdvrtd| j D ]\}}t|tr*tdi || j|< qd S )Nrk   zTargets: invalid targets type)z1.0z1.0.0zTargets: invalid spec versionr&   )rL   rT   rM   rk   rU   rV   rW   rf   rX   r&   r&   r'   r[      s   


zTargets.__post_init__N)r0   r1   r2   r>   r?   r   r   rf   rR   rJ   r[   r&   r&   r&   r'   rj      s   
 rj   c                   @   s6   e Zd ZU ee ed< eed< dZeed< dd Z	dS )SignedTargetsr]   r^   r   rR   c                 C   r_   r`   )ra   rb   r]   rV   rW   r:   r^   rj   rc   r&   r&   r'   r[      re   zSignedTargets.__post_init__N)
r0   r1   r2   rF   r:   r?   rj   rR   rJ   r[   r&   r&   r&   r'   rl      s
   
 rl   c                   @   r9   )
TargetFilepathrawNr=   r&   r&   r&   r'   rm      r@   rm   c                   @   sj   e Zd ZU dZeee  ed< dZee	 ed< e
jedZee ed< e
jedZee ed< dd ZdS )	AgentPayloadNrootsrk   )default_factorytarget_filesclient_configsc              
   C   s   | j d ur*tt| j D ]}t| j | tr)tdi tt	| j | | j |< qt| j
tr?tdi tt	| j
| _
tt| jD ]}t| j| tr]tdi | j| | j|< qFd S r`   )rq   ra   rb   rV   r>   r\   jsonloadsbase64	b64decoderk   rl   rs   rW   rm   rc   r&   r&   r'   r[      s   
&zAgentPayload.__post_init__)r0   r1   r2   rq   r   rF   r\   r?   rk   rl   dataclassesfieldrs   rm   setrt   r>   r[   r&   r&   r&   r'   rp      s   
 rp   c                   @   s  e Zd ZdZdRddZdedefddZd	ee	 ddfd
dZ
dd ZdededdfddZdeddfddZdeddfddZdeej ddfddZdededefddZdeddfddZdefddZdRddZdSd!eddfd"d#ZdSd!eddfd$d%ZdRd&d'Zd(edeeeef  fd)d*Ze d(e!d+ed,e"dee#eef  fd-d.Z$d/eeef deeef fd0d1Z%deeef fd2d3Z&e d4e'e	 d5e(d+ed6e"ddf
d7d8Z)d4e'e	 d9e*d:e+d;e+ddf
d<d=Z,d4e'e	 d9e*d:e+d(e!ddf
d>d?Z-d@dA Z.dBe/e dCe'e0 ddfdDdEZ1e dCe'e0 dFe2d:e+ddfdGdHZ3d4e'e	 ddfdIdJZ4d(e!de5ee ee ee+ f fdKdLZ6dMeeef ddfdNdOZ7defdPdQZ8dS )TRemoteConfigClientz
    The Remote Configuration client regularly checks for updates on the agent
    and dispatches configurations to registered products.
    r!   Nc                 C   s@  t  }tt | _tj| _ddi| _t	j
d}|d ur%| jt| tjj }t| tjjr:tjj|d< tjjrDtjj|d< ||d< t |d< tt d|tjjttj tjjtjjd	d
 | D d| _tj  }rx|| jd< g | _!i | _"t# | _$t% | _&t'| j&| j(d| _)i | _*d| _+d | _,d | _-d| _.d S )Nzcontent-typezapplication/json+_DD_REMOTE_CONFIGURATION_ADDITIONAL_HEADERSenvrR   tracer_version	host_namepythonc                 S   s   g | ]}d  |qS ):joinr#   r&   r&   r'   
<listcomp>   s    z/RemoteConfigClient.__init__.<locals>.<listcomp>)
runtime_idlanguager   serviceextra_servicesr~   app_versiontagsr
   GlobalSubscriberr   )/r   r>   uuiduuid4idagent_configtrace_agent_url	agent_url_headersosenvirongetupdater   ddtracer   r   copyr	   add_tagsr~   rR   r   rW   r   get_runtime_idr   rF   _get_extra_servicesrU   _client_tracerr
   process_tags_listcached_target_files_product_callbacksr{   _enabled_productsr   _global_connectorr   _dispatch_to_products_global_subscriber_applied_configs_last_targets_version_last_error_backend_state_capabilities)rY   r   additional_header_strr   p_tags_listr&   r&   r'   __init__   sN   






zRemoteConfigClient.__init__capabilitiesc                 C   s"   t || d d d S )N      big)rw   	b64encodeto_bytes
bit_lengthdecode)rY   r   r&   r&   r'   _encode_capabilities	  s   "z'RemoteConfigClient._encode_capabilitiespayloadsc                 C   s  | j  }| D ]W\}}z<tdt t | t }|	  W d   n1 s,w   Y  |
  }tkrHtjtjd|dd| dd W q	 ty`   tjdt t |d	d
 Y q	w |sedS i }|D ]}|jr|jjr|jj}||vr~g ||< || | qi| D ]d\}}	||}
|
durz?tdt t t|	| t }|
|	 W d   n1 sw   Y  |
  }tkrtjtjd|dd| dd W q ty   tjdt t |d	d
 Y qw qdS )a  Dispatch payloads from the global subscriber to registered product callbacks.

        This method runs in child processes and performs the following:
        1. Calls periodic() on all registered callbacks (happens every poll cycle)
        2. Groups payloads by product and dispatches them to their callbacks

        Args:
            payloads: Sequence of configuration payloads to dispatch
        z2[%s][P: %s] Calling periodic method for product %sNz(Periodic RC operation exceeded thresholdperiodicz%.3f)productcallback_typeelapsed_time)r   z8[%s][P: %s] Error calling periodic method for product %sTexc_infoz1[%s][P: %s] Dispatching %d payloads to product %sz(RC callback operation exceeded thresholdpayloadz+[%s][P: %s] Error dispatching to product %s)r   r   rU   logdebugr   getpidgetppidr   r   elapsed$CALLBACK_EXECUTION_WARNING_THRESHOLDr   add_logr   WARNING	Exceptionerrormetadataproduct_nameappendr   rb   )rY   r   product_callbacksr   callbackswr   product_payloadsr   product_payload_listproduct_callbackr&   r&   r'   r     s   

	
	

	
z(RemoteConfigClient._dispatch_to_productsc                 C   s*   t t | _t | jd< | j  d S )Nr   )	r>   r   r   r   r   r   r   r   clearrY   r&   r&   r'   renew_idg  s   zRemoteConfigClient.renew_idr   r   c                 C   s&   || j |< tdt t | dS )a  
        Register a product callback for the single-subscriber architecture.

        Args:
            product_name: Name of the product (e.g., "ASM_FEATURES", "LIVE_DEBUGGING")
            callback: Callback function to invoke when payloads are received in child processes
        z.[%s][P: %s] Registered callback for product %sNr   r   r   r   r   r   rY   r   r   r&   r&   r'   register_callbackm  s   
z$RemoteConfigClient.register_callbackc                 C   (   | j | tdt t | dS )ab  
        Enable a product to be included in client payloads sent to the agent.

        Enabling a product means it will be added to the 'products' list in the
        payload, signaling to the agent that this client wants to receive
        configurations for this product.

        Args:
            product_name: Name of the product to enable
        z[%s][P: %s] Enabled product %sN)r   addr   r   r   r   r   rY   r   r&   r&   r'   enable_product|     z!RemoteConfigClient.enable_productc                 C   r   )af  
        Disable a product, removing it from client payloads sent to the agent.

        The product's callback will remain registered and can still receive
        configurations if the agent sends them, but the client will not
        request configurations for this product.

        Args:
            product_name: Name of the product to disable
        z[%s][P: %s] Disabled product %sN)r   discardr   r   r   r   r   r   r&   r&   r'   disable_product  r   z"RemoteConfigClient.disable_productc                 C   s   |D ]	}|  j |O  _ qd S r"   )r   )rY   r   
capabilityr&   r&   r'   add_capabilities  s   z#RemoteConfigClient.add_capabilitiesc                 C   s4   || j v r|| j |< tdt t | dS dS )z-Update the callback for a registered product.z+[%s][P: %s] Updated callback for product %sTFr   r   r&   r&   r'   update_product_callback  s
   

z*RemoteConfigClient.update_product_callbackc                 C   s*   | j |d tdt t | dS )zUnregister a product.Nz#[%s][P: %s] Unregistered product %s)r   popr   r   r   r   r   r   r&   r&   r'   unregister_product  s   z%RemoteConfigClient.unregister_productc                 C   s   | j jtjkS )z*Check if the global subscriber is running.)r   statusr   RUNNINGr   r&   r&   r'   is_subscriber_running  s   z(RemoteConfigClient.is_subscriber_runningc                 C   s0   |   s| j  tdt t  dS dS )z#Start the global subscriber thread.z%[%s][P: %s] Started global subscriberN)r   r   startr   r   r   r   r   r   r&   r&   r'   start_subscriber  s   
z#RemoteConfigClient.start_subscriberFr   c                 C   s4   |   r| jj|d tdt t  dS dS )z"Stop the global subscriber thread.r   z%[%s][P: %s] Stopped global subscriberN)r   r   stopr   r   r   r   r   rY   r   r&   r&   r'   stop_subscriber  s   z"RemoteConfigClient.stop_subscriberc                 C   s(   | j j|d tdt t  dS )z%Restart the global subscriber thread.r   z'[%s][P: %s] Restarted global subscriberN)r   force_restartr   r   r   r   r   r   r&   r&   r'   restart_subscriber  s   z%RemoteConfigClient.restart_subscriberc                 C   s   t  | _t | _dS )z3Clear all registered products and enabled products.N)rW   r   r{   r   r   r&   r&   r'   reset_products  s   z!RemoteConfigClient.reset_productsr   c              
   C   s  d }zzft jrtdt t | tj| j	t
jd}|dt|| j | }|jd}|d urRt|dkrRtdt t  W W |d urP|  d S d S | }t jrhtdt t |d W n& ty } ztd	t| W Y d }~W |d ur|  d S d S d }~ww W |d ur|  n
|d ur|  w w |jd
krd S |jdk s|jdkrtd|j|j d S t|S )Nz"[%s][P: %s] RC request payload: %s)timeoutPOSTzContent-Lengthr   z%[%s][P: %s] RC response payload emptyz#[%s][P: %s] RC response payload: %szutf-8z?Unexpected connection error in remote config client request: %si     i,  z1Unexpected error: HTTP error status %s, reason %s)r   r-   r   r   r   r   r   r   get_connectionr   r   trace_agent_timeout_secondsrequestr   r   getresponseheadersr   rJ   closereadr   OSErrorr>   r   reasonru   rv   )rY   r   connrespdata_lengthdataer&   r&   r'   _send_request  sN   	


z RemoteConfigClient._send_requesttargetr   c                    s    fdd| j D }t|dks|d d u r%td dd | j D  d S z	t|d }W n ty<   td w t	
| }||jkrStd ||jzt|W S  tyg   td	 w )
Nc                    s   g | ]
}|j  kr|jqS r&   )rn   ro   r$   itemr   r&   r'   r     s    z;RemoteConfigClient._extract_target_file.<locals>.<listcomp>   r   z-invalid target_files for %r. target files: %sc                 S   s   g | ]}|j qS r&   rn   r  r&   r&   r'   r         z$invalid base64 target_files for {!r}z0mismatch between target {!r} hashes {!r} != {!r}z$invalid JSON content for target {!r})rs   rb   r   r   rw   rx   r   r7   formathashlibsha256	hexdigestsha256_hashru   rv   )r   r   r   
candidatesro   computed_hashr&   r  r'   _extract_target_file  s*   
z'RemoteConfigClient._extract_target_filestatec              
   C   sD   t tj | jd< tt| jt | jd| j|| | j	d| j
dS )Nr   T)r   products	is_tracerclient_tracerr  r   )clientr   )rF   r   r   r   r   rW   r   r   r   r   r   )rY   r  r&   r&   r'   _build_payload  s   
z!RemoteConfigClient._build_payloadc                 C   sR   | j d u}td| jdd | j D |d}| jd ur | j|d< |r'| j |d< |S )Nr  c              	   S   sF   g | ]}|j rt|j|j|j|j|j d nt|j|j|j|jdqS ))r   rR   r   apply_stateapply_error)r   rR   r   r  )r  rW   r   tuf_versionr   r  )r$   r   r&   r&   r'   r     s"    z3RemoteConfigClient._build_state.<locals>.<listcomp>)root_versiontargets_versionconfig_states	has_errorbackend_client_stater   )r   rW   r   r   valuesr   )rY   r  r  r&   r&   r'   _build_state  s   



zRemoteConfigClient._build_statepayload_listconfig_contentconfig_metadatac                 C   s   |  t||| dS )z=Accumulate a payload to be published to the global connector.N)r   r   )r  r   r   r!  r&   r&   r'   _accumulate_payload,  s   z&RemoteConfigClient._accumulate_payloadapplied_configsrt   rk   c           	   	   C   s   t  }| j D ]G\}}||||kr|||< q||vr d }nq|j| jv rOztdt	 t
 | | |||| W q tyN   td|j| Y qw qd S )Nz'[%s][P: %s] Disabling configuration: %sz)error while removing product %s config %r)objectr   rU   r   r   r   r   r   r   r   r   r"  r   )	rY   r  r#  rt   rk   witnessr   r   callback_actionr&   r&   r'   )_remove_previously_applied_configurations6  s$   z<RemoteConfigClient._remove_previously_applied_configurationsc           
   	   C   s   |  D ]`\}}|j| jv rd| j|}||krq| |||}|d u r%qztdt	 t
 | | |||| W n! ty\   d||jf }	tj|	dd d|_|	|_|||< Y qw d|_|||< qd S )Nz/[%s][P: %s] Load new configuration: %s. contentz/Failed to apply configuration %s for product %rTr         )rU   r   r   r   r   r  r   r   r   r   r   r"  r   r  r  )
rY   r  r#  rt   r   r   r   applied_configr   error_messager&   r&   r'   _load_new_configurationsQ  s.   z+RemoteConfigClient._load_new_configurationsc                 C   sP   | j r#g }| j  D ]\}}|||jd|jdgd q
|| _d S g | _d S )Nr	  )	algorithmhash)rn   rg   rh   )r   rU   r   rg   r  r   )rY   cached_datar   r   r&   r&   r'   _add_apply_config_to_cachep  s   

z-RemoteConfigClient._add_apply_config_to_cachepayload_client_configspayload_target_filesc                 C   s<   dd |D }| dd | jD }t||kstdd S )Nc                 S   s   h | ]}|j qS r&   r  r#   r&   r&   r'   	<setcomp>  r  zMRemoteConfigClient._validate_config_exists_in_target_paths.<locals>.<setcomp>c                 S   s   h | ]}|d  qS r  r&   r#   r&   r&   r'   r3    s    z/Not all client configurations have target files)unionr   r{   r7   )rY   r1  r2  pathsr&   r&   r'   '_validate_config_exists_in_target_paths  s
   z:RemoteConfigClient._validate_config_exists_in_target_pathspayload_targets_signedc                 C   sB   | D ]}|j r|j |js|r||jstd|jf qd S )Nz=target file %s not exists in client_config and signed targets)rk   r   rn   r7   )r2  r7  rt   r   r&   r&   r'   _validate_signed_target_files  s   

z0RemoteConfigClient._validate_signed_target_filesc                 C   s4   |sdS t dt t t| | j| dS )z9Publish all accumulated payloads to the global connector.Nz6[%s][P: %s] Publishing %d payloads to global connector)r   r   r   r   r   rb   r   write)rY   r  r&   r&   r'   _publish_configuration  s   z)RemoteConfigClient._publish_configurationc              	   C   s   |j d u rdS |j j}t }|j  D ]0\}}t|}|d u r'td|| \}}}	}t	|	||j
d|j|jdd||< q|jd}
|j|
|fS )N)NNNzunexpected target format {!r}r	  r4   )r   r   r  rg   r  opaque_backend_state)rk   r^   rW   rU   TARGET_FORMATmatchr7   r  groupsr   rh   r   rg   ri   rR   )rY   r   r^   rk   r   r   mr%   r   	config_idbackend_stater&   r&   r'   _process_targets  s$   



z#RemoteConfigClient._process_targetsr   c           
   
      s&  z	t di | W n ty& } ztjd|dd d| }t|d }~ww |  j j  jd u r6d S | 	 \}}}|d u sF|d u rHd S  fdd|
 D }tdt t || |  j jj| t }g }	| |	||| | |	||  | |	 || _|| _|| _|   d S )	Nz"invalid agent payload received: %rTr   z invalid agent payload received: c                    s    i | ]\}}| j v r||qS r&   )rt   )r$   rZ   r4   r   r&   r'   
<dictcomp>  s     z8RemoteConfigClient._process_response.<locals>.<dictcomp>z8[%s][P: %s] Retrieved client configs last version %s: %sr&   )rp   r   r   r   r7   r6  rt   rs   rk   rB  rU   r   r   r   r8  r^   rW   r'  r,  r:  r   r   r   r0  )
rY   r   r   msglast_targets_versionrA  rk   rt   r#  r  r&   rC  r'   _process_response  s@   


z$RemoteConfigClient._process_responsec              
   C   s   z#|   }t| |}| |}|d u rW dS | | d | _W dS  tyB } zt|| _t	j
ddd W Y d }~dS d }~w tyR   t	j
ddd Y dS  tyb   t	j
ddd Y dS w )NFTz-remote configuration client reported an errorr   zUnexpected response datazUnexpected error)r  ru   dumpsr  r   rG  r   r7   r>   r   r   rT   r   )rY   r  r   responser   r&   r&   r'   r     s*   


zRemoteConfigClient.request)r!   N)F)9r0   r1   r2   r8   r   rJ   r>   r   r   r   r   r   r   r   r   r   r   enumIntFlagr   r5   r   r   r   r   r   r   r   r   r   r   r   staticmethodrp   r   rW   r  r  r  rF   r   r"  AppliedConfigTypeTargetsTyper'  r,  r0  r{   rm   r6  rj   r8  r:  tuplerB  rG  r   r&   r&   r&   r'   r|      s    
9[


"(" 	



(-r|   )Srw   ry   rJ  r  ru   r   retypingr   r   r   r   r   r   r   r   ddtrace.internalr   r	   r
   r   ddtrace.internal.hostnamer   ddtrace.internal.loggerr   ddtrace.internal.packagesr   ddtrace.internal.remoteconfigr   r   r   r   )ddtrace.internal.remoteconfig._connectorsr   *ddtrace.internal.remoteconfig._subscribersr   'ddtrace.internal.remoteconfig.constantsr   ddtrace.internal.servicer    ddtrace.internal.settings._agentr   r   ddtrace.internal.settings._corer   ddtrace.internal.telemetryr   $ddtrace.internal.telemetry.constantsr   ddtrace.internal.utils.formatsr   ddtrace.internal.utils.timer   ddtrace.internal.utils.versionr   r0   r   compiler<  r   	frozensetr+   r5   r,   r    r   r7   	dataclassr:   rA   rG   rK   r\   rf   rj   rl   rm   rp   rW   r>   rM  rN  r|   r&   r&   r&   r'   <module>   s    

	