Beispiel #1
0
    def create_ciminstance(self):
        """
        Create a sample instance with multiple properties and
        property types.
        """
        class TZ(tzinfo):
            """'Simplistic tsinfo subclass for this test"""
            def utcoffset(self, dt):  # pylint: disable=unused-argument
                return timedelta(minutes=-399)

        dt = datetime(year=2016,
                      month=3,
                      day=31,
                      hour=19,
                      minute=30,
                      second=40,
                      microsecond=654321,
                      tzinfo=MinutesFromUTC(120))
        cim_dt = CIMDateTime(dt)
        props_input = {
            'S1':
            b'Ham',
            'Bool':
            True,
            'UI8':
            Uint8(42),
            'UI16':
            Uint16(4216),
            'UI32':
            Uint32(4232),
            'UI64':
            Uint64(4264),
            'SI8':
            Sint8(-42),
            'SI16':
            Sint16(-4216),
            'SI32':
            Sint32(-4232),
            'SI64':
            Sint64(-4264),
            'R32':
            Real32(42.0),
            'R64':
            Real64(42.64),
            'DTI':
            CIMDateTime(timedelta(10, 49, 20)),
            'DTF':
            cim_dt,
            'DTP':
            CIMDateTime(datetime(2014, 9, 22, 10, 49, 20, 524789,
                                 tzinfo=TZ())),
        }
        # TODO python 2.7 will not write the following unicode character
        # For the moment, only add this property in python 3 test
        if six.PY3:
            props_input['S2'] = u'H\u00E4m'  # U+00E4 = lower case a umlaut

        inst = CIMInstance('CIM_Foo', props_input)
        return inst
Beispiel #2
0
    def uint16(num):
        """Convert number to uint16 WBEM client type if needed"""

        if getTesterCfg().isWMI:
            return num
        else:
            from pywbem import Uint16
            return Uint16(num)
Beispiel #3
0
 def test_single_valued(self):
     """Single-valued properties"""
     self._run_single(CIMProperty('Spotty', 'Foot'))
     self._run_single(CIMProperty('Age', Uint16(32)))
     self._run_single(CIMProperty('Foo', '', type='string'))
     self._run_single(CIMProperty('Foo', None, type='string'))
     self._run_single(CIMProperty('Age', None, type='uint16',
                                  qualifiers={'Key': CIMQualifier('Key',
                                                                  True)}))
Beispiel #4
0
    def test_invoke_method(self):
        """
        Emulates call to invokemethod to test parameter processing.
        Currently creates the pywbem_request component.
        Each test emulated a single cim operation with fixed data to
        create the input for the yaml, create the yaml, and test the result
        """
        obj_name = self.create_ciminstancename()

        params = [
            ('StringParam', 'Spotty'),
            ('Uint8', Uint8(1)),
            ('Sint8', Sint8(2)),
            ('Uint16', Uint16(3)),
            ('Sint16', Sint16(3)),
            ('Uint32', Uint32(4)),
            ('Sint32', Sint32(5)),
            ('Uint64', Uint64(6)),
            ('Sint64', Sint64(7)),
            ('Real32', Real32(8)),
            ('Real64', Real64(9)),
            ('Bool', True),
            ('DTN', CIMDateTime.now()),
            # ('DTI', timedelta(60)),
            ('Ref', obj_name)
        ]

        self.test_recorder.stage_pywbem_args(method='InvokeMethod',
                                             MethodName='Blah',
                                             ObjectName=obj_name,
                                             Params=params)
        method_result_tuple = None
        method_exception = None
        self.test_recorder.stage_pywbem_result(method_result_tuple,
                                               method_exception)
        self.test_recorder.record_staged()

        # reload the yaml to test created values
        test_yaml = self.loadYamlFile()
        test_yaml = test_yaml[0]
        pywbem_request = test_yaml['pywbem_request']
        self.assertEqual(pywbem_request['url'], 'http://acme.com:80')
        operation = pywbem_request['operation']
        self.assertEqual(operation['pywbem_method'], 'InvokeMethod')
        self.assertEqual(operation['MethodName'], 'Blah')

        param_dict = dict(params)
        self.assertEqual(len(param_dict), 14)

        self.assertEqual(param_dict['StringParam'], 'Spotty')
        self.assertEqual(param_dict['Uint8'], 1)
        self.assertEqual(param_dict['Bool'], True)
        # test other parameters
        ref = param_dict['Ref']
        self.assertEqual(ref, obj_name)
Beispiel #5
0
def get_cim_rps(c):
    cim_rps = []
    for n in INTEROP_NAMESPACES:
        try:
            cim_rps = c.EnumerateInstances('CIM_RegisteredProfile',
                                           namespace=n, localonly=False)
        except CIMError as e:
            if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
               e[0] == pywbem.CIM_ERR_INVALID_NAMESPACE or \
               e[0] == pywbem.CIM_ERR_INVALID_CLASS:
                pass
            else:
                raise

        if len(cim_rps):
            for cim_rp in cim_rps:
                if cim_rp['RegisteredOrganization'] == Uint16(11) and \
                        'Array' == cim_rp['RegisteredName']:
                    return cim_rp
    return None
Beispiel #6
0
    def test_all(self):

        # Single-valued properties

        self._run_single(CIMProperty('Spotty', 'Foot'))
        self._run_single(CIMProperty('Age', Uint16(32)))
        self._run_single(CIMProperty('Foo', '', type='string'))
        self._run_single(CIMProperty('Foo', None, type='string'))
        self._run_single(
            CIMProperty('Age',
                        None,
                        type='uint16',
                        qualifiers={'Key': CIMQualifier('Key', True)}))

        # Property arrays

        self._run_single(CIMProperty('Foo', ['a', 'b', 'c']))
        self._run_single(CIMProperty('Foo', None, type='string',
                                     is_array=True))
        self._run_single(
            CIMProperty('Foo', [Uint8(x) for x in [1, 2, 3]],
                        qualifiers={'Key': CIMQualifier('Key', True)}))

        # Reference properties

        self._run_single(CIMProperty('Foo', None, type='reference'))
        self._run_single(CIMProperty('Foo', CIMInstanceName('CIM_Foo')))
        self._run_single(
            CIMProperty('Foo',
                        CIMInstanceName('CIM_Foo'),
                        qualifiers={'Key': CIMQualifier('Key', True)}))

        # EmbeddedObject properties

        inst = CIMInstance('Foo_Class', {'one': Uint8(1), 'two': Uint8(2)})
        self._run_single(CIMProperty('Foo', inst))
        self._run_single(CIMProperty('Foo', [inst]))
Beispiel #7
0
        obj=b"abc",
        exp_type_name=u'string',
    ), None, None, True),

    # Integer tests
    ("Object is an integer", dict(
        obj=42,
        exp_type_name=None,
    ), TypeError, None, True),
    ("Object is a Uint8 number", dict(
        obj=Uint8(42),
        exp_type_name=u'uint8',
    ), None, None, True),
    ("Object is a Uint16 number",
     dict(
         obj=Uint16(42),
         exp_type_name=u'uint16',
     ), None, None, True),
    ("Object is a Uint32 number",
     dict(
         obj=Uint32(42),
         exp_type_name=u'uint32',
     ), None, None, True),
    ("Object is a Uint64 number",
     dict(
         obj=Uint64(42),
         exp_type_name=u'uint64',
     ), None, None, True),
    ("Object is a Sint8 number", dict(
        obj=Sint8(42),
        exp_type_name=u'sint8',
    def CreateInstance(self, namespace, new_instance):
        # pylint: disable=invalid-name
        """
        Create an instance of the CIM_IndicationFilter class in an Interop
        namespace of the CIM repository, and if not yet existing create the new
        namespace in the CIM repository.

        See `~pywbem_mock.InstanceWriteProvider.CreateInstance` for
        documentation of validation and description of input parameters, noting
        extra conditions for this provider as described below:

        Parameters:

          namespace (:term:`string`):
            Must be a valid Interop namespace.

          new_instance (:class:`~pywbem.CIMInstance`):
            The following applies regarding its properties:
            * The 'Filter' and 'Handler' reference properties must exist.

            * If 'SubscriptionDuration' exists, 'SubscriptionTimeRemaining'
              will be set.
            * 'CreationClassName' property: This property is required and its
              value must match the class name of the new instance.

        Raises:

          :exc:`~pywbem.CIMError`: (CIM_ERR_INVALID_PARAMETER) if namespace
            is not the Interop namespace in the CIM repository or the Name
            property does not exist or the other properties cannot be added to
            the instance.
        """
        self.parameter_is_interop(namespace, new_instance.classname)

        required_properties = ["Filter", "Handler"]

        self.validate_required_properties_exist(new_instance, namespace,
                                                required_properties)

        # Add missing properties that the might come from CIM_IndicationService

        new_instance['SubscriptionStartTime'] = CIMDateTime.now()
        new_instance['TimeOfLastStateChange'] = CIMDateTime.now()

        # Conditionally add the following properties
        set_property(new_instance, 'OnFatalErrorPolicy', Uint16(2))

        set_property(new_instance, 'RepeatNotificationPolicy', Uint16(2))

        set_property(new_instance, 'SubscriptionState', Uint16(2))

        if 'SubscriptionDuration' in new_instance:
            new_instance['SubscriptionTimeRemaining'] = \
                new_instance['SubscriptionDuration']
        else:
            new_instance['SubscriptionDuration'] = CIMProperty(
                'SubscriptionDuration', None, type='uint64')

        set_property(new_instance, 'SubscriptionInfo',
                     CIMProperty('SubscriptionInfo', None, type='string'))

        set_property(new_instance, 'Description',
                     "Pywbem mock CIMIndicationSubscriptionProvider instance")

        # Create the CIM instance for the new namespace in the CIM repository,
        # by delegating to the default provider method.
        return super(CIMIndicationSubscriptionProvider,
                     self).CreateInstance(namespace, new_instance)
    def CreateInstance(self, namespace, new_instance):
        # pylint: disable=invalid-name
        """
        Create an instance of the CIM_ListenerDestinationCIMXML class in an
        Interop namespace of the CIM repository, and if not yet existing create
        the new namespace in the CIM repository.

        See `~pywbem_mock.InstanceWriteProvider.CreateInstance` for
        documentation of validation and description of input parameters, noting
        extra conditions for this provider as described below:

        Parameters:

          namespace (:term:`string`):
            Must be a valid Interop namespace.

          new_instance (:class:`~pywbem.CIMInstance`):
            The following applies regarding its properties:
            * 'Name' property: This property is required since it defines the
              name of the new namespace to be created.
            * 'CreationClassName' property: This property is required and its
              value must match the class name of the new instance.

        Raises:

          :exc:`~pywbem.CIMError`: (CIM_ERR_INVALID_PARAMETER) if namespace
            is not the Interop namespace in the CIM repository or the Name
            property does not exist or the other properties cannot be added to
            the instance.
        """
        self.parameter_is_interop(namespace, new_instance.classname)

        ccn_pname = 'CreationClassName'
        name_pname = 'Name'
        sys_pname = 'SystemName'
        sccn_pname = 'SystemCreationClassName'

        required_properties = [name_pname]

        # Validate that required properties are specified in the new instance
        self.validate_required_properties_exist(new_instance, namespace,
                                                required_properties)

        # Validate  or fix other key values in the new instance
        def _fix_key_prop(pname, new_prop_value, replacement=None):
            if pname not in new_instance or \
                    new_instance[pname].lower != new_prop_value.lower():
                new_instance[pname] = replacement or new_prop_value

        # Set the keys to default if they don't exist or have invalid value
        _fix_key_prop(ccn_pname, new_instance.classname,
                      new_instance.classname)
        _fix_key_prop(sys_pname, SYSTEMNAME)
        _fix_key_prop(sccn_pname, SYSTEMCREATIONCLASSNAME)

        # Add missing properties that the might come from CIM_IndicationService
        # if not already in instance
        set_property(new_instance, 'Protocol', Uint16(2))

        set_property(new_instance, 'PersistenceType', Uint16(2))

        set_property(new_instance, 'Description',
                     "pywbem mock CIMListenerDestinationProvider instance")

        # Create the CIM instance for the new namespace in the CIM repository,
        # by delegating to the default provider method.
        return super(CIMListenerDestinationProvider,
                     self).CreateInstance(namespace, new_instance)
Beispiel #10
0
    def test_all(self):

        # Invoke on classname

        try:
            self.cimcall(self.conn.InvokeMethod, 'FooMethod', TEST_CLASS)

        except CIMError as ce:
            if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
                raise

        # Invoke on an InstanceName

        inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS)
        self.assertTrue(len(inst_names) >= 1)
        name = inst_names[0]  # Pick the first returned instance

        try:

            self.cimcall(self.conn.InvokeMethod, 'FooMethod', name)

        except CIMError as ce:
            if ce.args[0] not in (CIM_ERR_METHOD_NOT_AVAILABLE,
                                  CIM_ERR_METHOD_NOT_FOUND):
                raise

        # Test remote instance name

        name2 = name.copy()
        name2.host = 'woot.com'
        name2.namespace = 'root/cimv2'

        try:
            self.cimcall(self.conn.InvokeMethod, 'FooMethod', name)

        except CIMError as ce:
            if ce.args[0] not in (CIM_ERR_METHOD_NOT_AVAILABLE,
                                  CIM_ERR_METHOD_NOT_FOUND):
                raise

        # Call with all possible parameter types

        try:
            self.cimcall(self.conn.InvokeMethod,
                         'FooMethod',
                         TEST_CLASS,
                         String='Spotty',
                         Uint8=Uint8(1),
                         Sint8=Sint8(2),
                         Uint16=Uint16(3),
                         Sint16=Sint16(3),
                         Uint32=Uint32(4),
                         Sint32=Sint32(5),
                         Uint64=Uint64(6),
                         Sint64=Sint64(7),
                         Real32=Real32(8),
                         Real64=Real64(9),
                         Bool=True,
                         Date1=CIMDateTime.now(),
                         Date2=timedelta(60),
                         Ref=name)
        except CIMError as ce:
            if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
                raise

        # Call with non-empty arrays

        try:

            self.cimcall(self.conn.InvokeMethod,
                         'FooMethod',
                         TEST_CLASS,
                         StringArray='Spotty',
                         Uint8Array=[Uint8(1)],
                         Sint8Array=[Sint8(2)],
                         Uint16Array=[Uint16(3)],
                         Sint16Array=[Sint16(3)],
                         Uint32Array=[Uint32(4)],
                         Sint32Array=[Sint32(5)],
                         Uint64Array=[Uint64(6)],
                         Sint64Array=[Sint64(7)],
                         Real32Array=[Real32(8)],
                         Real64Array=[Real64(9)],
                         BoolArray=[False, True],
                         Date1Array=[CIMDateTime.now(),
                                     CIMDateTime.now()],
                         Date2Array=[timedelta(0), timedelta(60)],
                         RefArray=[name, name])

        except CIMError as ce:
            if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
                raise

        # Call with new Params arg

        try:
            self.cimcall(
                self.conn.InvokeMethod,
                'FooMethod',
                TEST_CLASS,
                [('Spam', Uint16(1)), ('Ham', Uint16(2))],  # Params
                Drink=Uint16(3),  # begin of **params
                Beer=Uint16(4))
        except CIMError as ce:
            if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE:
                raise
Beispiel #11
0
class SmisCommon(object):
    # Even many CIM_XXX_Service in DMTF shared the same return value
    # definition as SNIA do, but there is no DMTF standard motioned
    # InvokeMethod() should follow that list of return value.
    # We use SNIA definition here.
    # SNIA 1.6 rev4 Block book, BSP 5.5.3.12 Return Values section.
    SNIA_INVOKE_OK = 0
    SNIA_INVOKE_NOT_SUPPORTED = 1
    SNIA_INVOKE_FAILED = 4
    SNIA_INVOKE_ASYNC = 4096

    SNIA_BLK_ROOT_PROFILE = 'Array'
    SNIA_BLK_SRVS_PROFILE = 'Block Services'
    SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite'
    SNIA_MULTI_SYS_PROFILE = 'Multiple Computer System'
    SNIA_MASK_PROFILE = 'Masking and Mapping'
    SNIA_GROUP_MASK_PROFILE = 'Group Masking and Mapping'
    SNIA_FC_TGT_PORT_PROFILE = 'FC Target Ports'
    SNIA_ISCSI_TGT_PORT_PROFILE = 'iSCSI Target Ports'
    SNIA_SPARE_DISK_PROFILE = 'Disk Sparing'
    SMIS_SPEC_VER_1_1 = '1.1'
    SMIS_SPEC_VER_1_4 = '1.4'
    SMIS_SPEC_VER_1_5 = '1.5'
    SMIS_SPEC_VER_1_6 = '1.6'
    SNIA_REG_ORG_CODE = Uint16(11)
    _MEGARAID_NAMESPACE = 'root/LsiMr13'
    _NETAPP_E_NAMESPACE = 'root/LsiArray13'
    _PRODUCT_MEGARAID = 'LSI MegaRAID'
    _PRODUCT_NETAPP_E = 'NetApp-E'

    JOB_RETRIEVE_NONE = 0
    JOB_RETRIEVE_VOLUME = 1
    JOB_RETRIEVE_VOLUME_CREATE = 2

    IAAN_WBEM_HTTP_PORT = 5988
    IAAN_WBEM_HTTPS_PORT = 5989

    _INVOKE_MAX_LOOP_COUNT = 60
    _INVOKE_CHECK_INTERVAL = 5

    def __init__(self, url, username, password,
                 namespace=dmtf.DEFAULT_NAMESPACE,
                 no_ssl_verify=False, debug_path=None, system_list=None):
        self._wbem_conn = None
        self._profile_dict = {}
        self.root_blk_cim_rp = None    # For root_cim_
        self._vendor_product = None     # For vendor workaround codes.
        self.system_list = system_list
        self._debug_path = debug_path

        if namespace is None:
            namespace = dmtf.DEFAULT_NAMESPACE

        self._wbem_conn = pywbem.WBEMConnection(
            url, (username, password), namespace)
        if no_ssl_verify:
            try:
                self._wbem_conn = pywbem.WBEMConnection(
                    url, (username, password), namespace,
                    no_verification=True)
            except TypeError:
                # pywbem is not holding fix from
                # https://bugzilla.redhat.com/show_bug.cgi?id=1039801
                pass

        if debug_path is not None:
            self._wbem_conn.debug = True

        if namespace.lower() == SmisCommon._MEGARAID_NAMESPACE.lower():
        # Skip profile register check on MegaRAID for better performance.
        # MegaRAID SMI-S profile support status will not change for a while.
            self._profile_dict = {
                # Provide a fake profile support status to pass the check.
                SmisCommon.SNIA_BLK_ROOT_PROFILE: SmisCommon.SMIS_SPEC_VER_1_4,
                SmisCommon.SNIA_BLK_SRVS_PROFILE: SmisCommon.SMIS_SPEC_VER_1_4,
                SmisCommon.SNIA_DISK_LITE_PROFILE:
                SmisCommon.SMIS_SPEC_VER_1_4,
            }
            self._vendor_product = SmisCommon._PRODUCT_MEGARAID
        else:
            (self._profile_dict, self.root_blk_cim_rp) = \
                _profile_register_load(self._wbem_conn)

        if namespace.lower() == SmisCommon._NETAPP_E_NAMESPACE.lower():
            self._vendor_product = SmisCommon._PRODUCT_NETAPP_E
            # NetApp-E indicates they support 1.0 version of FC/iSCSI target
            # But 1.0 does not define thoese profiles. Forcly change
            # support version to 1.4
            self._profile_dict[SmisCommon.SNIA_FC_TGT_PORT_PROFILE] = \
                SmisCommon.SMIS_SPEC_VER_1_4
            self._profile_dict[SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE] = \
                SmisCommon.SMIS_SPEC_VER_1_4
            # NetApp-E indicates support of Mask and Mapping 1.2. But
            # SNIA website link for 1.2 broken. Change it to 1.4.
            self._profile_dict[SmisCommon.SNIA_MASK_PROFILE] = \
                SmisCommon.SMIS_SPEC_VER_1_4

        # Check 'Array' 1.4 support status.
        _profile_check(
            self._profile_dict, SmisCommon.SNIA_BLK_ROOT_PROFILE,
            SmisCommon.SMIS_SPEC_VER_1_4, raise_error=True)

    def profile_check(self, profile_name, spec_ver, raise_error=False):
        """
        Usage:
            Check whether we support certain profile at certain SNIA
            specification version or later version.
            Will raise LsmError(ErrorNumber.NO_SUPPORT, 'xxx') if raise_error
            is True when nothing found.
        Parameter:
            profile_name    # SmisCommon.SNIA_XXXX_PROFILE
            spec_ver        # SmisCommon.SMIS_SPEC_VER_XXX
            raise_error     # Raise LsmError if not found
        Returns:
            True
                or
            False
        """
        return _profile_check(
            self._profile_dict, profile_name, spec_ver, raise_error)

    def _vendor_namespace(self):
        if self.root_blk_cim_rp:
            cim_syss_path = self._wbem_conn.AssociatorNames(
                self.root_blk_cim_rp.path,
                ResultClass='CIM_ComputerSystem',
                AssocClass='CIM_ElementConformsToProfile')
            if len(cim_syss_path) == 0:
                raise LsmError(
                    ErrorNumber.NO_SUPPORT,
                    "Target SMI-S provider does not support any "
                    "CIM_ComputerSystem for SNIA SMI-S '%s' profile" %
                    SmisCommon.SNIA_BLK_ROOT_PROFILE)
            return cim_syss_path[0].namespace
        else:
            raise LsmError(
                ErrorNumber.PLUGIN_BUG,
                "_vendor_namespace(): self.root_blk_cim_rp not set yet")

    def EnumerateInstances(self, ClassName, namespace=None, **params):
        if self._wbem_conn.default_namespace in dmtf.INTEROP_NAMESPACES:
            # We have to enumerate in vendor namespace
            self._wbem_conn.default_namespace = self._vendor_namespace()
        params['LocalOnly'] = False
        return self._wbem_conn.EnumerateInstances(
            ClassName, namespace, **params)

    def EnumerateInstanceNames(self, ClassName, namespace=None, **params):
        if self._wbem_conn.default_namespace in dmtf.INTEROP_NAMESPACES:
            # We have to enumerate in vendor namespace
            self._wbem_conn.default_namespace = self._vendor_namespace()
        params['LocalOnly'] = False
        return self._wbem_conn.EnumerateInstanceNames(
            ClassName, namespace, **params)

    def Associators(self, ObjectName, **params):
        return self._wbem_conn.Associators(ObjectName, **params)

    def AssociatorNames(self, ObjectName, **params):
        return self._wbem_conn.AssociatorNames(ObjectName, **params)

    def GetInstance(self, InstanceName, **params):
        params['LocalOnly'] = False
        return self._wbem_conn.GetInstance(InstanceName, **params)

    def DeleteInstance(self, InstanceName, **params):
        return self._wbem_conn.DeleteInstance(InstanceName, **params)

    def References(self, ObjectName, **params):
        return self._wbem_conn.References(ObjectName, **params)

    def is_megaraid(self):
        return self._vendor_product == SmisCommon._PRODUCT_MEGARAID

    def is_netappe(self):
        return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E

    @staticmethod
    def cim_job_pros():
        return ['InstanceID']

    def cim_job_of_job_id(self, job_id, property_list=None):
        """
        Return CIM_ConcreteJob for given job_id.
        """
        if property_list is None:
            property_list = SmisCommon.cim_job_pros()
        else:
            property_list = merge_list(
                property_list, SmisCommon.cim_job_pros())

        cim_jobs = self.EnumerateInstances(
            'CIM_ConcreteJob',
            PropertyList=property_list)
        real_job_id = SmisCommon.parse_job_id(job_id)[0]
        for cim_job in cim_jobs:
            if md5(cim_job['InstanceID']) == real_job_id:
                return cim_job

        raise LsmError(
            ErrorNumber.NOT_FOUND_JOB,
            "Job %s not found" % job_id)

    @staticmethod
    def _job_id_of_cim_job(cim_job, retrieve_data, method_data):
        """
        Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
        with '@%s' % retrieve_data
        retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
        SmisCommon.JOB_RETRIEVE_VOLUME or etc
        method_data is any string a method would like store for error
        handling by job_status().
        """
        return "%s@%d@%s" % (
            md5(cim_job['InstanceID']), int(retrieve_data), str(method_data))

    @staticmethod
    def parse_job_id(job_id):
        """
        job_id is assembled by a md5 string, retrieve_data and method_data
        This method will split it and return
        (md5_str, retrieve_data, method_data)
        """
        tmp_list = job_id.split('@', 3)
        md5_str = tmp_list[0]
        retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
        method_data = None
        if len(tmp_list) == 3:
            retrieve_data = int(tmp_list[1])
            method_data = tmp_list[2]
        return (md5_str, retrieve_data, method_data)

    def _dump_wbem_xml(self, file_prefix):
        """
        When debugging issues with providers it's helpful to have
        the xml request/reply to give to provider developers.
        """
        try:
            if self._debug_path is not None:
                if not os.path.exists(self._debug_path):
                    os.makedirs(self._debug_path)

                if os.path.isdir(self._debug_path):
                    debug_fn = "%s_%s" % (
                        file_prefix, datetime.datetime.now().isoformat())
                    debug_full = os.path.join(
                        self._debug_path, debug_fn)

                    # Dump the request & reply to a file
                    with open(debug_full, 'w') as d:
                        d.write("REQUEST:\n%s\n\nREPLY:\n%s\n" %
                                (self._wbem_conn.last_request,
                                 self._wbem_conn.last_reply))
        except Exception:
            # Lets not bother to try and report that we couldn't log the debug
            # data when we are most likely already in a bad spot
            pass

    def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
                      error_handler=None, retrieve_data=None,
                      method_data=None):
        """
        cmd
            A string of command, example:
                'CreateOrModifyElementFromStoragePool'
        cim_path
            the CIMInstanceName, example:
                CIM_StorageConfigurationService.path
        in_params
            A dictionary of input parameter, example:
                {'ElementName': volume_name,
                 'ElementType': dmtf_element_type,
                 'InPool': cim_pool_path,
                 'Size': pywbem.Uint64(size_bytes)}
        out_handler
            A reference to a method to parse output, example:
                self._new_vol_from_name
        error_handler
            A reference to a method to handle all exceptions.
        retrieve_data
            SmisCommon.JOB_RETRIEVE_XXX, it will be used only
            when a ASYNC job has been created.
        method_data
            A string which will be stored in job_id, it could be used by
            job_status() to do error checking.
        """
        if retrieve_data is None:
            retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
        try:
            (rc, out) = self._wbem_conn.InvokeMethod(
                cmd, cim_path, **in_params)

            # Check to see if operation is done
            if rc == SmisCommon.SNIA_INVOKE_OK:
                if out_handler is None:
                    return None, None
                else:
                    return None, out_handler(out)

            elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
                # We have an async operation
                job_id = SmisCommon._job_id_of_cim_job(
                    out['Job'], retrieve_data, method_data)
                return job_id, None
            elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
                raise LsmError(
                    ErrorNumber.NO_SUPPORT,
                    'SMI-S error code indicates operation not supported')
            else:
                self._dump_wbem_xml(cmd)
                raise LsmError(ErrorNumber.PLUGIN_BUG,
                               "Error: %s rc= %s" % (cmd, str(rc)))

        except Exception:
            exc_info = sys.exc_info()
            # Make sure to save off current exception as we could cause
            # another when trying to dump debug data.
            self._dump_wbem_xml(cmd)
            if error_handler is not None:
                error_handler(self, method_data, exc_info)
            else:
                raise

    def invoke_method_wait(self, cmd, cim_path, in_params,
                           out_key=None, expect_class=None,
                           flag_out_array=False):
        """
        InvokeMethod and wait it until done.
        Return a CIMInstanceName from out[out_key] or from cim_job:
            CIM_ConcreteJob
                |
                | CIM_AffectedJobElement
                v
            CIMInstanceName # expect_class
        If flag_out_array is True, return the first element of out[out_key].
        """
        (rc, out) = self._wbem_conn.InvokeMethod(cmd, cim_path, **in_params)

        try:
            if rc == SmisCommon.SNIA_INVOKE_OK:
                if out_key is None:
                    return None
                if out_key in out:
                    if flag_out_array:
                        if len(out[out_key]) == 1:
                            return out[out_key][0]
                        else:
                            raise LsmError(
                                ErrorNumber.PLUGIN_BUG,
                                "invoke_method_wait(), output contains %d " %
                                len(out[out_key]) +
                                "elements: %s" % out[out_key])
                    return out[out_key]
                else:
                    raise LsmError(ErrorNumber.PLUGIN_BUG,
                                   "invoke_method_wait(), %s not exist "
                                   "in out %s" % (out_key, out.items()))

            elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
                cim_job_path = out['Job']
                loop_counter = 0
                job_pros = ['JobState', 'ErrorDescription',
                            'OperationalStatus']
                cim_xxxs_path = []
                while(loop_counter <= SmisCommon._INVOKE_MAX_LOOP_COUNT):
                    cim_job = self.GetInstance(cim_job_path,
                                               PropertyList=job_pros)
                    job_state = cim_job['JobState']
                    if job_state in (dmtf.JOB_STATE_NEW,
                                     dmtf.JOB_STATE_STARTING,
                                     dmtf.JOB_STATE_RUNNING):
                        loop_counter += 1
                        time.sleep(SmisCommon._INVOKE_CHECK_INTERVAL)
                        continue
                    elif job_state == dmtf.JOB_STATE_COMPLETED:
                        if not SmisCommon.cim_job_completed_ok(cim_job):
                            raise LsmError(
                                ErrorNumber.PLUGIN_BUG,
                                str(cim_job['ErrorDescription']))
                        if expect_class is None:
                            return None
                        cim_xxxs_path = self.AssociatorNames(
                            cim_job.path,
                            AssocClass='CIM_AffectedJobElement',
                            ResultClass=expect_class)
                        break
                    else:
                        raise LsmError(
                            ErrorNumber.PLUGIN_BUG,
                            "invoke_method_wait(): Got unknown job state "
                            "%d: %s" % (job_state, cim_job.items()))

                if loop_counter > SmisCommon._INVOKE_MAX_LOOP_COUNT:
                    raise LsmError(
                        ErrorNumber.TIMEOUT,
                        "The job generated by %s() failed to finish in %ds" %
                        (cmd,
                         SmisCommon._INVOKE_CHECK_INTERVAL *
                         SmisCommon._INVOKE_MAX_LOOP_COUNT))

                if len(cim_xxxs_path) == 1:
                    return cim_xxxs_path[0]
                else:
                    raise LsmError(
                        ErrorNumber.PLUGIN_BUG,
                        "invoke_method_wait(): got unexpected(not 1) "
                        "return from CIM_AffectedJobElement: "
                        "%s, out: %s, job: %s" %
                        (cim_xxxs_path, out.items(), cim_job.items()))
            else:
                self._dump_wbem_xml(cmd)
                raise LsmError(
                    ErrorNumber.PLUGIN_BUG,
                    "invoke_method_wait(): Got unexpected rc code "
                    "%d, out: %s" % (rc, out.items()))
        except Exception:
            exc_info = sys.exc_info()
            # Make sure to save off current exception as we could cause
            # another when trying to dump debug data.
            self._dump_wbem_xml(cmd)
            raise exc_info[0], exc_info[1], exc_info[2]

    def _cim_srv_of_sys_id(self, srv_name, sys_id, raise_error):
        property_list = ['SystemName']

        try:
            cim_srvs = self.EnumerateInstances(
                srv_name,
                PropertyList=property_list)
            for cim_srv in cim_srvs:
                if cim_srv['SystemName'] == sys_id:
                    return cim_srv
        except CIMError:
            if raise_error:
                raise
            else:
                return None

        if raise_error:
            raise LsmError(
                ErrorNumber.NO_SUPPORT,
                "Cannot find any '%s' for requested system ID" % srv_name)
        return None

    def cim_scs_of_sys_id(self, sys_id, raise_error=True):
        """
        Return a CIMInstance of CIM_StorageConfigurationService for given
        system id.
        Using 'SystemName' property as system id of a service which is defined
        by DMTF CIM_Service.
        """
        return self._cim_srv_of_sys_id(
            'CIM_StorageConfigurationService', sys_id, raise_error)

    def cim_rs_of_sys_id(self, sys_id, raise_error=True):
        """
        Return a CIMInstance of CIM_ReplicationService for given system id.
        Using 'SystemName' property as system id of a service which is defined
        by DMTF CIM_Service.
        """
        return self._cim_srv_of_sys_id(
            'CIM_ReplicationService', sys_id, raise_error)

    def cim_gmms_of_sys_id(self, sys_id, raise_error=True):
        """
        Return a CIMInstance of CIM_GroupMaskingMappingService for given system
        id.
        Using 'SystemName' property as system id of a service which is defined
        by DMTF CIM_Service.
        """
        return self._cim_srv_of_sys_id(
            'CIM_GroupMaskingMappingService', sys_id, raise_error)

    def cim_ccs_of_sys_id(self, sys_id, raise_error=True):
        """
        Return a CIMInstance of CIM_ControllerConfigurationService for given
        system id.
        Using 'SystemName' property as system id of a service which is defined
        by DMTF CIM_Service.
        """
        return self._cim_srv_of_sys_id(
            'CIM_ControllerConfigurationService', sys_id, raise_error)

    def cim_hwms_of_sys_id(self, sys_id, raise_error=True):
        """
        Return a CIMInstance of CIM_StorageHardwareIDManagementService for
        given system id.
        Using 'SystemName' property as system id of a service which is defined
        by DMTF CIM_Service.
        """
        return self._cim_srv_of_sys_id(
            'CIM_StorageHardwareIDManagementService', sys_id, raise_error)

    @staticmethod
    def cim_job_completed_ok(status):
        """
        Given a concrete job instance, check the operational status.  This
        is a little convoluted as different SMI-S proxies return the values in
        different positions in list :-)
        """
        rc = False
        op = status['OperationalStatus']

        if (len(op) > 1 and
            ((op[0] == dmtf.OP_STATUS_OK and
              op[1] == dmtf.OP_STATUS_COMPLETED) or
             (op[0] == dmtf.OP_STATUS_COMPLETED and
              op[1] == dmtf.OP_STATUS_OK))):
            rc = True

        return rc
Beispiel #12
0
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; If not, see <http://www.gnu.org/licenses/>.
#
# Author: Gris Ge <*****@*****.**>

# This class handle DMTF CIM constants and convert to LSM type.

from pywbem import Uint16

# CIM_StorageHardwareID['IDType']
ID_TYPE_OTHER = Uint16(1)
ID_TYPE_WWPN = Uint16(2)
ID_TYPE_ISCSI = Uint16(5)

TGT_PORT_USAGE_FRONTEND_ONLY = Uint16(2)
TGT_PORT_USAGE_UNRESTRICTED = Uint16(4)
# CIM_FCPort['PortDiscriminator']
FC_PORT_PORT_DISCRIMINATOR_FCOE = Uint16(10)
# CIM_NetworkPort['LinkTechnology']
NET_PORT_LINK_TECH_ETHERNET = Uint16(2)
# CIM_iSCSIProtocolEndpoint['Role']
ISCSI_TGT_ROLE_TARGET = Uint16(3)
# CIM_SCSIProtocolController['NameFormat']
SPC_NAME_FORMAT_ISCSI = Uint16(3)
# CIM_IPProtocolEndpoint['IPv6AddressType']
IPV6_ADDR_TYPE_GUA = Uint16(6)