
    Hg>3                        d dl mZmZmZmZmZ d dlmZ d dlZd dl	Z	 e	j
        e          Z G d de          Z G d de          Z G d d	e          Z G d
 de          Z G d de          Z G d de          ZdS )    )TupleOptionalAnyUnionIterator)DeviceNc                       e Zd ZdS )_MatchInvalidN)__name__
__module____qualname__     J/usr/lib/python3/dist-packages/ceph/deployment/drive_selection/matchers.pyr
   r
      s        Dr   r
   c                   $    e Zd ZdZd Zd Zd ZdS )Matcherz} The base class to all Matchers

    It holds utility methods such as _get_disk_key
    and handles the initialization.

    c                 0    || _         || _        d| _        dS )z Initialization of Base class

        :param str key: Attribute like 'model, size or vendor'
        :param str value: Value of attribute like 'X123, 5G or samsung'
         N)keyvaluefallback_keyselfr   r   s      r   __init__zMatcher.__init__   s      
r   c                    |                                 }dt          t          t          f         dt          dt
          t                   ffdt           || j                            }|s%| j        rt           || j                            }|r|d         S t          d	                    | j        | j                            )am   Helper method to safely extract values form the disk dict

        There is a 'key' and a _optional_ 'fallback' key that can be used.
        The reason for this is that the output of ceph-volume is not always
        consistent (due to a bug currently, but you never know).
        There is also a safety measure for a disk_key not existing on
        virtual environments. ceph-volume apparently sources its information
        from udev which seems to not populate certain fields on VMs.

        :raises: A generic Exception when no disk_key could be found.
        :return: A disk value
        :rtype: str
        nodekey_valreturnc              3     K   t          | t                    r| D ]} ||          D ]}|V  dS t          | t                    r8|| v r
| |         V  |                                 D ]} ||          D ]}|V  dS dS )z( Find keys in non-flat dict recursively N)
isinstancelistdictvalues)r   r   ir   jfindkeyss        r   r&   z'Matcher._get_disk_key.<locals>.findkeys9   s      $%% 	" " "A'x733 " "!				"" " D$'' "d??w-''' " "A'x733 " "!				"	" "" "r   r   zNo value found for {} or {})
to_jsonr   r!   r"   strr   r   r   r
   format)r   devicedisk
disk_valuer&   s       @r   _get_disk_keyzMatcher._get_disk_key%   s    $ ~~	"5t, 	"s 	"x} 	" 	" 	" 	" 	" 	" ((42233
 	Ad/ 	AhhtT->??@@J 	.a=  = D D$+!- !- . . .r   c                     t           )z Implements a valid comparison method for a SubMatcher
        This will get overwritten by the individual classes

        :param dict disk: A disk representation
        )NotImplementedErrorr   r+   s     r   comparezMatcher.compareP   s
     "!r   N)r   r   r   __doc__r   r-   r1   r   r   r   r   r      sL         	 	 	). ). ).V" " " " "r   r   c                        e Zd ZdZddZd ZdS )SubstringMatcherz  Substring matcher subclass
    Nc                 L    t                               | ||           || _        d S Nr   r   r   r   r   r   r   s       r   r   zSubstringMatcher.__init___   s(    sE***(r   c                 h    |sdS |                      |          }t          | j                  |v rdS dS )z Overwritten method to match substrings

        This matcher does substring matching
        :param dict disk: A disk representation (see base for examples)
        :return: True/False if the match succeeded
        :rtype: bool
        FT)r-   r(   r   )r   r+   r,   s      r   r1   zSubstringMatcher.compared   sA      	5''--
tz??j((4ur   r6   r   r   r   r2   r   r1   r   r   r   r4   r4   [   sA         ) ) ) )
    r   r4   c                        e Zd ZdZddZd ZdS )
AllMatcherz All matcher subclass
    Nc                 L    t                               | ||           || _        d S r6   r7   r8   s       r   r   zAllMatcher.__init__z   s*     	sE***(r   c                     |sdS dS )a    Overwritten method to match all

        A rather dumb matcher that just accepts all disks
        (regardless of the value)
        :param dict disk: A disk representation (see base for examples)
        :return: always True
        :rtype: bool
        FTr   r0   s     r   r1   zAllMatcher.compare   s      	5tr   r6   r:   r   r   r   r<   r<   v   sA         ) ) ) )    r   r<   c                       e Zd ZdZd Zd ZdS )EqualityMatcherz Equality matcher subclass
    c                 >    t                               | ||           d S r6   )r   r   r   s      r   r   zEqualityMatcher.__init__   s"     	sE*****r   c                     |sdS |                      |          }|| j        k    }|s3t                              d                    || j                             |S )z Overwritten method to match equality

        This matcher does value comparison
        :param dict disk: A disk representation
        :return: True/False if the match succeeded
        :rtype: bool
        Fz{} != {})r-   r   loggerdebugr)   )r   r+   r,   rets       r   r1   zEqualityMatcher.compare   sb      	5''--
DJ& 	DLL**:tzBBCCC
r   Nr:   r   r   r   r@   r@      s<         + + +
    r   r@   c                   n   e Zd ZdZg dg dg dfZed         ed         z   Zd Zed             Zej	        d	             Zed
             Z
e
j	        d             Z
ed             Zej	        d             Zed             Zed             Zed             ZddZed             Zed             Zd ZdS )SizeMatcherz Size matcher subclass
    )KBMBGBTB)KMGT)g     @@g    .Ag    eAg   mBr      c                     t                               | ||           d| _        d| _        d | _        d | _        d | _        d | _        d | _        d | _	        | 
                                 d S )Nhuman_readable_sizesize)r   r   r   r   _high_high_suffix_low_low_suffix_exact_exact_suffix_parse_filterr   s      r   r   zSizeMatcher.__init__   sp     	sE***("
 	!r   c                     | j         | j        fS )z# Getter for 'low' matchers
        rV   rW   r   s    r   lowzSizeMatcher.low   s    
 y$***r   c                 $    |\  | _         | _        dS )z# Setter for 'low' matchers
        Nr\   )r   r^   s     r   r^   zSizeMatcher.low   s    
 '*#	4###r   c                     | j         | j        fS )z$ Getter for 'high' matchers
        rT   rU   r]   s    r   highzSizeMatcher.high   s    
 z4,,,r   c                 $    |\  | _         | _        dS )z$ Setter for 'high' matchers
        Nra   )r   rb   s     r   rb   zSizeMatcher.high   s    
 )-%
D%%%r   c                     | j         | j        fS )z% Getter for 'exact' matchers
        rX   rY   r]   s    r   exactzSizeMatcher.exact   s    
 {D...r   c                 $    |\  | _         | _        dS )z% Setter for 'exact' matchers
        Nre   )r   rf   s     r   rf   zSizeMatcher.exact   s    
 +0'T'''r   c                    |                                 }|| j        vr"t          d                    |                    t	          t          | j        d         | j        d                                                 ||          S )a   Normalize any supported suffix

        Since the Drive Groups are user facing, we simply
        can't make sure that all users type in the requested
        form. That's why we have to internally agree on one format.
        It also checks if any of the supported suffixes was used
        and raises an Exception otherwise.

        :param str suffix: A suffix ('G') or ('M')
        :return: A normalized output
        :rtype: str
        zUnit '{}' not supportedrP   r   )uppersupported_suffixesr
   r)   r"   zipSUFFIXESget)clssuffixs     r   _normalize_suffixzSizeMatcher._normalize_suffix   s}     /// 9 @ @ H HIIICLOLO
 
   3vv	r   c                 ^    |                      t          j        d|          d                   S )z Wrapper method to find and normalize a prefix

        :param str obj: A size filtering string ('10G')
        :return: A normalized unit ('GB')
        :rtype: str
        z	[a-zA-Z]+r   )rp   refindall)rn   objs     r   _parse_suffixzSizeMatcher._parse_suffix  s)     $$RZc%B%B1%EFFFr   c                 b    t          j        d|          d         |                     |          fS )ai   Helper method to extract data from a string

        It uses regex to extract all digits and calls _parse_suffix
        which also uses a regex to extract all letters and normalizes
        the resulting suffix.

        :param str data: A size filtering string ('10G')
        :return: A Tuple with normalized output (10, 'GB')
        :rtype: tuple
        z	\d+\.?\d*r   )rr   rs   ru   )rn   datas     r   _get_k_vzSizeMatcher._get_k_v  s.     z,--a0#2C2CD2I2IIIr   r   Nc                 *   t          j        d| j                  }|^|                                                    d          \  }}|                     |          | _        |                     |          | _        t          j        d| j                  }|r,|                     |                                          | _        t          j        d| j                  }|r,|                     |                                          | _        t          j        d| j                  }|r,|                     |                                          | _        | j        s5| j        s0| j        s+t          d
                    | j                            dS dS dS )a   Identifies which type of 'size' filter is applied

        There are four different filtering modes:

        1) 10G:50G (high-low)
           At least 10G but at max 50G of size

        2) :60G
           At max 60G of size

        3) 50G:
           At least 50G of size

        4) 20G
           Exactly 20G in size

        This method uses regex to identify and extract this information
        and raises if none could be found.
        z\d+[A-Z]{1,2}:\d+[A-Z]{1,2}N:z\d+[A-Z]{1,2}:$z^:\d+[A-Z]{1,2}z^\d+\.?\d*[A-Z]{1,2}$zCouldn't parse {})rr   matchr   groupsplitrx   r^   rb   rf   r
   r)   )r   low_highlowparthighpartr^   rb   rf   s          r   rZ   zSizeMatcher._parse_filter'  sm   ( 8:DJGG ( 0 0 6 6s ; ;GX}}W--DHh//DIh)4:66 	2}}SYY[[11DHx*DJ77 	4djjll33DI14:>> 	6u{{}}55DJx 	H	 	H$* 	H 3 : :4: F FGGG	H 	H 	H 	H 	H 	Hr   c                     | \  }}|t          |          nd}t          t          t          j        d         t          j        d                                                 t          |          d          |z  S )z Convert any supported unit to bytes

        :param tuple tpl: A tuple with ('10', 'GB')
        :return: The converted byte value
        :rtype: float
        Ng        r      )floatr"   rk   rG   rl   rm   r(   )tplval_strro   r   s       r   to_bytezSizeMatcher.to_byteP  ss     ")"5g3C # #
 
   3s6{{D!!E* 	*r   c                 f    t                               t                               |                     S r6   )rG   r   rx   )inputs    r   str_to_bytezSizeMatcher.str_to_byteb  s&     "";#7#7#>#>???r   c                    |sdS |                      |          }|st                              d           dS t          j        d|          d         }|                     |          }|                     ||f          }t          | j                  rnt          | j	                  rZ||                     | j                  k    r ||                     | j	                  k    rdS t          
                    d           n>t          | j	                  rOt          | j                  s;||                     | j	                  k    rdS t          
                    d           nt          | j                  rOt          | j	                  s;||                     | j                  k    rdS t          
                    d           nxt          | j                  r;||                     | j                  k    rdS t          
                    d	           n)t          
                    d
           t          d          dS )z Convert MB/GB/TB down to bytes and compare

        1) Extracts information from the to-be-inspected disk.
        2) Depending on the mode, apply checks and return

        # This doesn't seem very solid and _may_
        be re-factored


        Fz!Could not retrieve value for diskz\d+\.\d+r   Tz'Disk didn't match for 'high/low' filterz"Disk didn't match for 'low' filterz#Disk didn't match for 'high' filterz$Disk didn't match for 'exact' filterz&Neither high, low, nor exact was givenzNo filters applied)r-   rC   warningrr   rs   ru   r   allrb   r^   rD   rf   r
   )r   r+   r,   	disk_sizedisk_suffixdisk_size_in_bytes         r   r1   zSizeMatcher.compareh  s     	5''--

  	NN>???5J{J77:	((44 LL)[)ABBty>> 	6c$(mm 	6 DLLI% %  #4TX8N8N#N#Nt LLBCCCC]] 	63ty>> 	6 DLL$:$:::tLL=>>>>^^ 	6CMM 	6 DLL$;$;;;tLL>????__ 	6 DLL$<$<<<tLL?@@@@LLABBB 4555ur   )r   N)r   r   r   r2   rl   rj   r   propertyr^   setterrb   rf   classmethodrp   ru   rx   rZ   staticmethodr   r   r1   r   r   r   rG   rG      s         	!  !!!H "!x{2  $ + + X+ 	Z* * Z* - - X- 
[- - [- / / X/ \0 0 \0   [, G G [G J J [J'H 'H 'H 'HR * * \*  @ @ \@
4 4 4 4 4r   rG   )typingr   r   r   r   r   ceph.deployment.inventoryr   rr   logging	getLoggerr   rC   	Exceptionr
   objectr   r4   r<   r@   rG   r   r   r   <module>r      s   9 8 8 8 8 8 8 8 8 8 8 8 8 8 , , , , , , 				 		8	$	$	 	 	 	 	I 	 	 	
E" E" E" E" E"f E" E" E"R    w   6       6    g   8o o o o o' o o o o or   