
    ([Qhp                         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m	Z	 	 d dl
Z
dZ	 d dlZdZ G d d      Zy# e$ r dZY w xY w# e$ r dZY !w xY w)	    N)getpass)_sos)is_executableTIMEOUT_DEFAULTTFc                      e Zd ZdZdZdZdZdZdZdZ	dZ
dZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZi d	dd
ddddg ddddddddddddddddddddddddddddiZd@dZd Zd Z e!d         Z"d! Z#d" Z$d# Z%d$ Z&d% Z'd& Z(d' Z)d( Z*d) Z+d* Z,d+ Z-dAd,Z.d- Z/d. Z0d/ Z1d0 Z2d1 Z3d2 Z4d3 Z5d4 Z6d5 Z7d6 Z8d7 Z9dAd8Z:d9 Z;dBd:Z<d; Z=dBd<Z>d= Z?dCd>Z@	 	 dDd?ZAy)EUploadTargetz
    This class is designed to upload files to a distribution
    defined location. These files can be either sos reports,
    sos collections, or other kind of files like: vmcores,
    application cores, logs, etc.

    z
            Upload a file (can be an sos report, a must-gather, or others) to
             a distribution defined remote location
            zGeneric UploadgenericN/zhttps://s3.amazonaws.com upload_filecase_idlow_priorityFprofiles
upload_urlupload_directoryupload_userupload_passupload_methodautoupload_no_ssl_verifyupload_protocolupload_s3_endpointupload_s3_regionupload_s3_bucketupload_s3_access_keyupload_s3_secret_keyupload_s3_object_prefixupload_targetc                 b    t        j                  d      | _        || _        || _        || _        y )Nsos_ui)logging	getLoggerui_logparsercmdlineargs)selfr$   r&   r%   s       =/usr/lib/python3/dist-packages/sos/upload/targets/__init__.py__init__zUploadTarget.__init__a   s)    ''1	    c                      y)aS  This should be overridden by upload targets

        This is called by sos upload on each target type that exists, and
        is meant to return True when the upload target matches a criteria
        that indicates that is the local upload target that should be used.

        Only the first upload target to determine a match is selectedF r'   s    r(   check_distributionzUploadTarget.check_distributionh   s     r*   c                     | j                   S )N)upload_target_idr-   s    r(   get_target_idzUploadTarget.get_target_idr   s    $$$r*   c                 f    | j                   r| j                   S | j                  j                         S )z-Returns the upload target's name as a string.)upload_target_name__name__lower)clss    r(   namezUploadTarget.nameu   s,     !!)))||!!##r*   c                     | j                   d   | j                   d   | j                   d   j                  | j                   d   j                  dS )Ncmdlineoptspolicy)r9   r:   r   r   )hook_commonsr   r   r-   s    r(   get_commonszUploadTarget.get_commons|   sP    ,,];''1((7?? $ 1 1- @
 	
r*   c                     || _         y)zMSet common host data for the Upload targets
            to reference
        N)commons)r'   r>   s     r(   set_commonszUploadTarget.set_commons   s     r*   c                    || _         | j                         | _        | j                  d   }| j                  d   }|j                  r|j	                          |j
                  | _        |j                  | _        |j                  | _        |j                  | _	        d| _
        |j                  | _        |j                  | _        |j                  | _        |j                  | _        |j                  | _        |j                   | _        |j"                  s|j$                  s| j'                         r0|j(                  dk(  s!| j+                          | j-                          nO|j(                  dk(  r@| j/                          | j1                          | j3                          | j5                          | j6                  j9                  d       y y y )Nr9   r:   r   s3)r;   r<   r>   r   _configure_low_priorityr   r   r   r   upload_passwordupload_archive_namer   r   r   r   r   r   batchquietget_upload_urlr   prompt_for_upload_userprompt_for_upload_passwordprompt_for_upload_s3_bucketprompt_for_upload_s3_endpointprompt_for_upload_s3_access_keyprompt_for_upload_s3_secret_keyr#   info)r'   r;   cmdline_optsr:   s       r(   pre_workzUploadTarget.pre_work   s   ('')||M2h'$$**,
 '11'33 , = =+77#% "."A"A , = =$0$E$E! , = ='3'K'K$$0$E$E! !!""""$$44<++-//1--5002224446446KKR  # "r*   c                     | j                         s?d| j                          d| j                          d}t        t	        |            | _        yy)zuShould be overridden by targets to determine if an access key needs
        to be provided for upload or not
        z0Please provide the upload access key for bucket  via endpoint : N)get_upload_s3_access_keyget_upload_s3_bucketget_upload_s3_endpointinput_r   r'   msgs     r(   rL   z,UploadTarget.prompt_for_upload_s3_access_key   s[     ,,.--/0 1//12"6 
 ).afD% /r*   c                     | j                         s6d| j                          d| j                          d}t        |      | _        yy)ztShould be overridden by targets to determine if a secret key needs
        to be provided for upload or not
        z0Please provide the upload secret key for bucket rR   rS   N)get_upload_s3_secret_keyrU   rV   r   r   rY   s     r(   rM   z,UploadTarget.prompt_for_upload_s3_secret_key   sW     ,,.--/0 1//12"6 
 )0D% /r*   c                    | j                   sq| j                  r;| j                  j                  d      r | j                  dd | _         | j                   S t        t	        d            }|j                  d      | _         | j                   S )zpShould be overridden by targets to determine if a bucket needs to
        be provided for upload or not
        s3://   Nz"Please provide the upload bucket: r
   )r   r   
startswithrW   rX   strip)r'   
user_inputs     r(   rJ   z(UploadTarget.prompt_for_upload_s3_bucket   sw     $$4??#=#=g#F(,(;% $$$ #1%I#JK
(2(8(8(=%$$$r*   c                     | j                   }| j                  s6d| j                          d| d}t        t	        |            }|xs || _        | j                  S )zsShould be overridden by targets to determine if an endpoint needs
        to be provided for upload or not
        z.Please provide the upload endpoint for bucket z (default: z): )_upload_s3_endpointr   rU   rW   rX   )r'   default_endpointrZ   rb   s       r(   rK   z*UploadTarget.prompt_for_upload_s3_endpoint   sk      33&&--/0./s4 
 qvJ&0&D4DD#&&&r*   c                     | j                         s.d| j                          d}t        t        |            | _        yy)zcShould be overridden by targets to determine if a user needs to
        be provided or not
        zPlease provide upload user for rS   N)get_upload_userrG   rW   rX   r   rY   s     r(   rH   z#UploadTarget.prompt_for_upload_user   s=     ##%3D4G4G4I3J"MC$QsV}D &r*   c                     | j                         sC| j                         | j                  k7  r%d| j                          d}t        |      | _        yyy)zrShould be overridden by targets to determine if a password needs to
        be provided for upload or not
        z'Please provide the upload password for rS   N)get_upload_passwordrg   _upload_userr   rC   rY   s     r(   rI   z'UploadTarget.prompt_for_upload_password   sZ     '')t/C/C/E/3/@/@0A<**,-R1C#*3<D 	0A)r*   c                    || _         | j                  s| j                         | _        | j                  st        d      | j	                         }| j
                  j                  t        d| j                                        |       S )a	  
        Entry point for sos attempts to upload the generated archive to a
        target or user specified location.

        Currently there is support for HTTPS, SFTP, and FTP. HTTPS uploads are
        preferred for target-defined defaults.

        Targets that need to override uploading methods should override the
        respective upload_https(), upload_sftp(), and/or upload_ftp() methods
        and should NOT override this method.

        :param archive: The archive filepath to use for upload
        :type archive: ``str``

        In order to enable this for a target, that target needs to implement
        the following:

        Required Class Attrs

        :_upload_url:     The default location to use. Note these MUST include
                          protocol header
        :_upload_user:    Default username, if any else None
        :_upload_password: Default password, if any else None

        The following Class Attrs may optionally be overidden by the Target

        :_upload_directory:     Default FTP server directory, if any


        The following methods may be overridden by ``Target`` as needed

        `prompt_for_upload_user()`
            Determines if sos should prompt for a username or not.

        `get_upload_user()`
            Determines if the default or a different username should be used

        `get_upload_https_auth()`
            Format authentication data for HTTPS uploads

        `get_upload_url_string()`
            Print a more human-friendly string than vendor URLs
        zBNo upload destination provided by upload target or by --upload-urlzAttempting upload to )	rD   r   rG   	Exception_determine_upload_typer#   rN   rX   get_upload_url_string)r'   archiveupload_funcs      r(   upload_archivezUploadTarget.upload_archive   s    X $+ "113DO 2 3 3113%d&@&@&B%CDE	
 }r*   c                 j   | j                   | j                  | j                  | j                  d}| j                  d   j
                  |v r|| j                  d   j
                     S d| j                  vrt        d      | j                  j                  d      \  }}||vrt        d|       ||   S )a  Based on the url provided, determine what type of upload to attempt.

        Note that this requires users to provide a FQDN address, such as
        https://myvendor.com/api or ftp://myvendor.com instead of
        myvendor.com/api or myvendor.com
        )ftpsftphttpsrA   r9   z://z#Must provide protocol in upload URLz&Unsupported or unrecognized protocol: )	
upload_ftpupload_sftpupload_https	upload_s3r>   r   r   rl   split)r'   protsprotrX   s       r(   rm   z#UploadTarget._determine_upload_type3  s     ??$$&&..	
 <<&66%?m4DDEE'ABB//''.auDTFKLLT{r*   c                     |s| j                         }|s| j                         }t        j                  j	                  ||      S )ah  Formats the user/password credentials using basic auth

        :param user: The username for upload
        :type user: ``str``

        :param password: Password for `user` to use for upload
        :type password: ``str``

        :returns: The user/password auth suitable for use in requests calls
        :rtype: ``requests.auth.HTTPBasicAuth()``
        )rg   ri   requestsauthHTTPBasicAuth)r'   userpasswords      r(   get_upload_https_authz"UploadTarget.get_upload_https_authI  s=     '')D//1H}}**4::r*   c                 f    t        j                  dd      xs | j                  xs | j                  S )zHelper function to determine if we should use the target default
        upload access key or one provided by the user

        :returns: The access_key to use for upload
        :rtype: ``str``
        SOSUPLOADS3ACCESSKEYN)osgetenvr   _upload_s3_access_keyr-   s    r(   rT   z%UploadTarget.get_upload_s3_access_key\  4     		0$7 +))+**	,r*   c                 R    | j                   s| j                          | j                   S )zHelper function to determine if we should use the target default
        upload endpoint or one provided by the user

        :returns: The S3 Endpoint to use for upload
        :rtype: ``str``
        )r   rK   r-   s    r(   rV   z#UploadTarget.get_upload_s3_endpointg  s%     &&..0&&&r*   c                 6    | j                   xs | j                  S )zHelper function to determine if we should use the target default
        upload region or one provided by the user

        :returns: The S3 region to use for upload
        :rtype: ``str``
        )r   _upload_s3_regionr-   s    r(   get_upload_s3_regionz!UploadTarget.get_upload_s3_regionr  s     $$>(>(>>r*   c                 >   | j                   r\| j                   j                  d      rA| j                   dd j                  dd      }|d   | _        t	        |      dkD  r
|d   | _        | j                  s| j                          | j                  xs | j                  S )zHelper function to determine if we should use the target default
        upload bucket or one provided by the user

        :returns: The S3 bucket to use for upload
        :rtype: ``str``
        r^   r_   Nr
      r   )r   r`   rz   r   lenr   rJ   _upload_s3_bucket)r'   bucket_and_prefixs     r(   rU   z!UploadTarget.get_upload_s3_bucket{  s     ??t99'B $ 3 9 9#q A$5a$8D!$%)/@/C,$$,,.$$>(>(>>r*   c                 6    | j                   xs | j                  S )zHelper function to determine if we should use the target default
        upload object prefix or one provided by the user

        :returns: The S3 object prefix to use for upload
        :rtype: ``str``
        )r   _upload_s3_object_prefixr-   s    r(   get_upload_s3_object_prefixz(UploadTarget.get_upload_s3_object_prefix  s     ++Lt/L/LLr*   c                 f    t        j                  dd      xs | j                  xs | j                  S )zHelper function to determine if we should use the target default
        upload secret key or one provided by the user

        :returns: The S3 secret key to use for upload
        :rtype: ``str``
        SOSUPLOADS3SECRETKEYN)r   r   r   _upload_s3_secret_keyr-   s    r(   r\   z%UploadTarget.get_upload_s3_secret_key  r   r*   c                     | j                   sQ| j                  rE| j                  r9| j                  r-| j	                         }| j                         }d| d| | _        | j                   xs | j                  S )zHelper function to determine if we should use the target default
        upload url or one provided by the user

        :returns: The URL to use for upload
        :rtype: ``str``
        r^   r
   )r   r   r   r   rU   r   _upload_url)r'   bucketprefixs      r(   rG   zUploadTarget.get_upload_url  sl     !!%%%%..0F557F!&vhax8D2$"2"22r*   c                 8    d}t        j                  |d|      }|S )Nz([^:]+://[^:]+:)([^@]+)(@.+)z\1********\3)resub)r'   urlpatternobfuscated_urls       r(   _get_obfuscated_upload_urlz'UploadTarget._get_obfuscated_upload_url  s    1#>r*   c                 @    | j                  | j                               S )zUsed by upload targets to potentially change the string used to
        report upload location from the URL to a more human-friendly string
        )r   rG   r-   s    r(   rn   z"UploadTarget.get_upload_url_string  s     ..t/B/B/DEEr*   c                 f    t        j                  dd      xs | j                  xs | j                  S )zHelper function to determine if we should use the target default
        upload user or one provided by the user

        :returns: The username to use for upload
        :rtype: ``str``
        SOSUPLOADUSERN)r   r   r   rj   r-   s    r(   rg   zUploadTarget.get_upload_user  s3     		/40 "  "!!	#r*   c                 f    t        j                  dd      xs | j                  xs | j                  S )a_  Helper function to determine if we should use the target default
        upload password or one provided by the user

        A user provided password, either via option or the 'SOSUPLOADPASSWORD'
        environment variable will have precendent over any target value

        :returns: The password to use for upload
        :rtype: ``str``
        SOSUPLOADPASSWORDN)r   r   rC   _upload_passwordr-   s    r(   ri   z UploadTarget.get_upload_password  s4     		-t4 &$$&%%	'r*   c                 8   t        d      st        d      	 ddl}d}|s| j	                         }|s| j                         }| j                         j                  dd      }d	| d
| }|j                  |d      }ddd|j                  |j                  g}	|j                  |	d      }
|
dk(  rd}n|
dk(  ro|j                  |       dd|j                  |j                  g}|j                  |d      dk(  }|s|j                          t        d| j                                |
dk(  rt        d| j                          d      |
dk(  rt        d| j                                |
dk(  rt        d|j                         |s,|j                          t        d| j                                d| j                    d | j#                          }|j                  |       d!|j                  |j                  d"g}|j                  |d#      }|dk(  r|j                  d$       y|dk(  rt        d%      |dk(  rt        d&|j                         |dk(  rt        d'      t        d(|j                         # t        $ r}t        d      |d}~ww xY w))a  Attempts to upload the archive to an SFTP location.

        Due to the lack of well maintained, secure, and generally widespread
        python libraries for SFTP, sos will shell-out to the system's local ssh
        installation in order to handle these uploads.

        Do not override this method with one that uses python-paramiko, as the
        upstream sos team will reject any PR that includes that dependency.
        rt   zSFTP is not locally supportedr   NzFSFTP upload requires python3-pexpect, which is not currently installedFzsftp://r   z sftp -oStrictHostKeyChecking=no @zutf-8)encodingzsftp>z	password:zConnection refused   timeoutTr   zPermission denied
   z#Incorrect username or password for    zConnection refused by z. Incorrect port?   z!Timeout hit trying to connect to    z,Unexpected error trying to connect to sftp: zUnable to connect via SFTP to zput  z100%zNo such file or directory   byezTimeout expired while uploadingzUnknown error during upload: z&Unable to write archive to destinationz!Unexpected response from server: )r   rl   pexpectImportErrorrg   ri   rG   replacespawnTIMEOUTEOFexpectsendlineclosern   beforerD   _get_sftp_upload_name)r'   r   r   r   errsftp_connectedsftp_urlsftp_cmdretsftp_expectsidxpass_expectsput_cmdput_expectsput_successs                  r(   rw   zUploadTarget.upload_sftp  s    V$;<<
	@
 '')D//1H &&(00B?5dV1XJGmmHwm7  OOKK
 jjrj2!8!NAXLL"#	L !ZZbZAQFN!		 E#'#=#=#?"@!B C CAX4#99;<<MO P PAX?#99;<> ? ?AXJ"zzl, - - IIK<#99;<> ? ? $223100235W OOKK'	
 jjcj:!LL!=>>!;CJJ<HII!DEE;CJJ<HII]  	@ 6 7<?@	@s   I? ?	JJJc                     | j                   j                  d      d   }| j                  r*t        j                  j                  | j                  |      }|S )a$  If a specific file name pattern is required by the SFTP server,
        override this method in the relevant Upload Target. Otherwise the
        archive's name on disk will be used

        :returns:       Filename as it will exist on the SFTP server
        :rtype:         ``str``
        r
   )rD   rz   r   r   pathjoin)r'   fnames     r(   r   z"UploadTarget._get_sftp_upload_name7  sG     ((..s3B7  GGLL!6!6>Er*   c                 v    t        j                  | j                         || j                         |t              S )zIf upload_https() needs to use requests.put(), use this method.

        Targets should override this method instead of the base upload_https()

        :param archive:     The open archive file object
        )datar   verifyr   )r~   putrG   r   r   )r'   ro   r   s      r(   _upload_https_putzUploadTarget._upload_https_putD  s5     ||D//1!%!;!;!=#)?D 	Dr*   c                     i S )zJDefine any needed headers to be passed with the POST request here
        r,   r-   s    r(   _get_upload_headersz UploadTarget._get_upload_headersO  s	     	r*   c                     d|j                   j                  d      d   || j                         fi}t        j                  | j                         || j                         |t              S )zIf upload_https() needs to use requests.post(), use this method.

        Targets should override this method instead of the base upload_https()

        :param archive:     The open archive file object
        filer
   r   )filesr   r   r   )r7   rz   r   r~   postrG   r   r   )r'   ro   r   r   s       r(   _upload_https_postzUploadTarget._upload_https_postT  sj     W\\'',R0'--/1
 }}T002%"&"<"<">$*OE 	Er*   c                 &   t         st        d      t        | j                  d      5 }| j                  d   j
                  dk(  r| j                  }n| j                  d   j
                  }| j                  d   j                  du }|dk(  r| j                  ||      }n| j                  ||      }|j                  dvr?|j                  dk(  rt        d	      t        d
|j                   d|j                         	 ddd       y# 1 sw Y   yxY w)zAttempts to upload the archive to an HTTPS location.

        :returns: ``True`` if upload is successful
        :rtype: ``bool``

        :raises: ``Exception`` if upload was unsuccessful
        z7Unable to upload due to missing python requests libraryrbr9   r   Fr   )      i  z/Authentication failed: invalid user credentialszPOST request returned rS   NT)REQUESTS_LOADEDrl   openrD   r>   r   _upload_methodr   r   r   status_codereason)r'   arcmethodr   rs        r(   rx   zUploadTarget.upload_httpsc  s     & ' ' $**D1 	S||M*88FB,,m4BB\\-0EENF**37++C8}}J.==C'#I   "8r#$88*!. / /#	 	 	s   CDDc                    ddl }ddl}|s| j                         }|t        d      |j	                  dd      }|s| j                         }|s| j                         }|s| j                  xs | j                  }	 |j                  |||d      }|st        d      |j                  |       t!        | j"                  d      5 }
|j%                  d| j"                  j                  d      d    |
       ddd       |j'                          y# |j                  $ r}t        d	|       |d}~w|j                  $ r}t        d
|       |d}~w|j                  $ rw}t        |      j                         d   }	|	dk(  rt        d| d      ||	dk(  rt        d| d      ||	dk(  rt        d|       |t        dt        |             |d}~ww xY w# 1 sw Y   xY w)aT  Attempts to upload the archive to either the target defined or user
        provided FTP location.

        :param url: The URL to upload to
        :type url: ``str``

        :param directory: The directory on the FTP server to write to
        :type directory: ``str`` or ``None``

        :param user: The user to authenticate with
        :type user: ``str``

        :param password: The password to use for `user`
        :type password: ``str``

        :returns: ``True`` if upload is successful
        :rtype: ``bool``

        :raises: ``Exception`` if upload in unsuccessful
        r   NzPno FTP server specified by upload target, use --upload-url to specify a locationzftp://r   r   r   z3connection failed, did you set a user and password?z timeout hit while connecting to zunable to connect to 503zcould not login as ''530zinvalid password for user '550z"could not set upload directory to z#error trying to establish session: r   zSTOR r
   r   T)ftplibsocketrG   rl   r   rg   ri   r   _upload_directoryFTPcwdr   gaierror
error_permstrrz   r   rD   
storbinaryquit)r'   r   	directoryr   r   r   r   sessionr   errno_arcfiles              r(   rv   zUploadTarget.upload_ftp  s   * 	%%'C; E F F kk(B''')D//1H--G1G1GI	jjdHbjAG !, - -KK	"" $**D1 	X0066s;B?@A8	 	+ ~~ 	O>seDE3N 	D3C59:C   
	HNN$Q'E~"6tfA >?SH~"=dV1 EFCO~ D#,+!/ 0589A#c(LM
		 	s=   ;3D 2GGD--G?EG A2GGG#c                    t         st        d      |s| j                         }|s| j                         }|s| j	                         j                  d      }|sJ| j                         }|dk7  r|j                  d      r|dd }|dk7  r|j                  d      s	|r| dnd}|s| j                         }|s| j                         }t        j                  d||||      }	 || j                  j                  d      d   z   }|j                  | j                  ||       y	# t        $ r}	t        d
t!        |	             |	d}	~	ww xY w)a  Attempts to upload the archive to an S3 bucket.

        :param endpoint: The S3 endpoint to upload to
        :type endpoint: str

        :param region: The S3 region to upload to
        :type region: str

        :param bucket: The name of the S3 bucket to upload to
        :type bucket: str

        :param prefix: The prefix for the S3 object/key
        :type prefix: str

        :param access_key: The access key for the S3 bucket
        :type access_key: str

        :param secret_key: The secret key for the S3 bucket
        :type secret_key: str

        :returns: True if upload is successful
        :rtype: bool

        :raises: Exception if upload is unsuccessful
        z4Unable to upload due to missing python boto3 libraryr
   r   r   NrA   )endpoint_urlregion_nameaws_access_key_idaws_secret_access_keyr   TzFailed to upload to S3: )BOTO3_LOADEDrl   rV   r   rU   ra   r   r`   endswithrT   r\   boto3clientrD   rz   r   r   )
r'   endpointregionr   r   
access_key
secret_key	s3_clientkeyes
             r(   ry   zUploadTarget.upload_s3  sW   6  & ' ' 224H..0F..066s;F557F| 1 1# 6|FOOC$8)/F81R668J668JLLH-33=7AC	
	H43399#>rBBC!!$":":"(#/ 	H6s1vh?@aG	Hs   ">D! !	E*EE)NNN)NN)T)NNNN)NNNNNN)Br4   
__module____qualname____doc__descr3   r0   _upload_filer   r   rj   r   r   rd   r   r   r   r   r   r   r   rC   r   r   r   r   r   r   r   arg_defaultsr)   r.   r1   classmethodr7   r<   r?   rP   rL   rM   rJ   rK   rH   rI   rq   rm   r   rT   rV   r   rU   r   r\   rG   r   rn   rg   ri   rw   r   r   r   r   rx   rv   ry   r,   r*   r(   r   r       sG   D * LKLN4  !JKO"Mr2 	 	B	
 	d 	D 	t 	t 	 	 	6 	d 	D 	D 	  	!" 	"4#$ 	%L*% $ $
(!T6
5
%'-06p,;&	,	'?? M	,3"
F	#'aJF	D
E>DL IM.2?Hr*   r   )r   r   r!   r   sosr   rX   sos.utilitiesr   r   r~   r   r   r  r  r   r,   r*   r(   <module>r     sl    
 	    8OL
gH gH  O  Ls    : A AAAA