def __get__(self, instance, cls=None): # Does the instance already have meta data if instance is not None and instance._meta: return instance._meta.href else: if hasattr(cls, 'typeof'): if instance is not None: element = fetch_href_by_name( instance.name, filter_context=instance.typeof) if element.json: instance._meta = Meta(**element.json[0]) return instance._meta.href raise ElementNotFound( 'Cannot find specified element: {}, type: {}'.format( unicode_to_bytes(instance.name), instance.typeof)) else: try: element = fetch_entry_point(cls.typeof) except UnsupportedEntryPoint as e: raise ElementNotFound(e) return element else: raise ElementNotFound( 'This class does not have the required attribute ' 'and cannot be referenced directly, type: {}'.format( instance))
def __get__(self, instance, cls=None): #Does the instance already have meta data if instance.meta: return instance.meta.href else: if hasattr(instance, 'typeof'): element = search.element_info_as_json_with_filter( instance.name, instance.typeof) if element: instance.meta = Meta(**element[0]) return instance.meta.href raise ElementNotFound( 'Cannot find specified element: {}, type: {}'.format( unicode_to_bytes(instance.name), instance.typeof)) elif isinstance(instance, smc.core.engine.Engine): element = search.element_info_as_json_with_filter( instance.name, 'engine_clusters') if element: instance.meta = Meta(**element[0]) return instance.meta.href raise LoadEngineFailed( 'Cannot load engine name: {}, ensure the ' 'name is correct and that the engine exists.'.format( instance.name)) else: raise ElementNotFound( 'This class does not have the required attribute ' 'and cannot be referenced directly, type: {}'.format( instance))
def get_or_create(cls, filter_key=None, **kwargs): """ Convenience method to retrieve an Element or create if it does not exist. If an element does not have a `create` classmethod, then it is considered read-only and the request will be redirected to :meth:`~get`. Any keyword arguments passed except the optional filter_key will be used in a create() call. If filter_key is provided, this should define an attribute and value to use for an exact match on the element. Valid attributes are ones required on the elements ``create`` method or can be viewed by the elements class docs. If no filter_key is provided, the name field will be used to find the element. :: >>> Network.get_or_create( filter_key={'ipv4_network': '123.123.123.0/24'}, name='mynetwork', ipv4_network='123.123.123.0/24') Network(name=mynetwork) The kwargs should be used to satisfy the elements ``create`` classmethod parameters to create in the event it cannot be found. :param dict filter_key: filter key represents the data attribute and value to use to find the element. If none is provided, the name field will be used. :param kwargs: keyword arguments mapping to the elements ``create`` method. :raises CreateElementFailed: could not create element with reason :raises ElementNotFound: if read-only element does not exist :return: element instance by type :rtype: Element """ if not hasattr(cls, 'create'): return cls.get(kwargs.get('name')) elif 'name' not in kwargs: raise ElementNotFound('Name field is a required parameter ' 'for all create type operations on an element') if filter_key: elements = cls.objects.filter(**filter_key) element = elements.first() if not element: element = cls.create(**kwargs) else: try: element = cls.get(kwargs.get('name')) except ElementNotFound: element = cls.create(**kwargs) return element
def get(cls, name, raise_exc=True): """ Get the element by name. Does an exact match by element type. :param str name: name of element :param bool raise_exc: optionally disable exception. :raises ElementNotFound: if element does not exist :rtype: Element """ element = cls.objects.filter(name, exact_match=True).first() if \ name is not None else None if not element and raise_exc: raise ElementNotFound('Cannot find specified element: %s, type: ' '%s' % (name, cls.__name__)) return element
def update_or_create(cls, filter_key=None, with_status=False, **kwargs): """ Update or create the element. If the element exists, update it using the kwargs provided if the provided kwargs are different from the existing value/s. When comparing values, strings and ints are compared normally. If a list is provided and is a list of strings, it will be compared and updated. If the list contains unhashable elements, it is automatically merged (i.e. list of dicts). If an element does not have a `create` classmethod, then it is considered read-only and the request will be redirected to :meth:`~get`. Provide a ``filter_key`` dict key/value if you want to match the element by a specific attribute and value. If no filter_key is provided, the name field will be used to find the element. :: >>> host = Host('kali') >>> print(host.address) 12.12.12.12 >>> host = Host.update_or_create(name='kali', address='10.10.10.10') >>> print(host, host.address) Host(name=kali) 10.10.10.10 :param dict filter_key: filter key represents the data attribute and value to use to find the element. If none is provided, the name field will be used. :param kwargs: keyword arguments mapping to the elements ``create`` method. :param bool with_status: if set to True, a 3-tuple is returned with (Element, modified, created), where the second and third tuple items are booleans indicating the status :raises CreateElementFailed: could not create element with reason :raises ElementNotFound: if read-only element does not exist :return: element instance by type :rtype: Element """ was_created, was_modified = False, False if not hasattr(cls, 'create'): return cls.get(kwargs.get('name')) elif 'name' not in kwargs: raise ElementNotFound( 'Name field is a required parameter ' 'for all create type operations on an element') element = None if filter_key: elements = cls.objects.filter(**filter_key) if elements.exists(): element = elements.first() else: try: element = cls.get(kwargs.get('name')) except ElementNotFound: element = None if element: params = {} for key, value in kwargs.items(): # Callable, Element or string if callable(value): value = value() elif isinstance(value, Element): value = value.href # Get value from element val = getattr(element, key, None) if isinstance(val, (string_types, int)): if val != value: params[key] = value elif isinstance(val, Element): if val.href != value: params[key] = value elif isinstance(val, list) and isinstance(value, list): try: # Try matching lists of strings if set(val) ^ set(value): params[key] = value except TypeError: # Unhashable, list of dicts? params[key] = value else: # Last ditch effort, might be comparing None to None if val != value: params[key] = value if params: element.update(**params) was_modified = True else: params = {k: v() if callable(v) else v for k, v in kwargs.items()} element = cls.create(**params) was_created = True if with_status: return element, was_modified, was_created return element
def get_or_create(cls, filter_key=None, with_status=False, **kwargs): """ Convenience method to retrieve an Element or create if it does not exist. If an element does not have a `create` classmethod, then it is considered read-only and the request will be redirected to :meth:`~get`. Any keyword arguments passed except the optional filter_key will be used in a create() call. If filter_key is provided, this should define an attribute and value to use for an exact match on the element. Valid attributes are ones required on the elements ``create`` method or can be viewed by the elements class docs. If no filter_key is provided, the name field will be used to find the element. :: >>> Network.get_or_create( filter_key={'ipv4_network': '123.123.123.0/24'}, name='mynetwork', ipv4_network='123.123.123.0/24') Network(name=mynetwork) The kwargs should be used to satisfy the elements ``create`` classmethod parameters to create in the event it cannot be found. :param dict filter_key: filter key represents the data attribute and value to use to find the element. If none is provided, the name field will be used. :param kwargs: keyword arguments mapping to the elements ``create`` method. :param bool with_status: if set to True, a tuple is returned with (Element, created), where the second tuple item indicates if the element has been created or not. :raises CreateElementFailed: could not create element with reason :raises ElementNotFound: if read-only element does not exist :return: element instance by type :rtype: Element """ was_created = False if 'name' not in kwargs: raise ElementNotFound( 'Name field is a required parameter ' 'for all create or update_or_create type operations on an element' ) if filter_key: elements = cls.objects.filter(**filter_key) element = elements.first() if elements.exists() else None else: try: element = cls.get(kwargs.get('name')) except ElementNotFound: if not hasattr(cls, 'create'): raise CreateElementFailed( '%s: %r not found and this element ' 'type does not have a create method.' % (cls.__name__, kwargs['name'])) element = None if not element: params = {k: v() if callable(v) else v for k, v in kwargs.items()} try: element = cls.create(**params) was_created = True except TypeError: raise CreateElementFailed( '%s: %r not found and missing ' 'constructor arguments to properly create.' % (cls.__name__, kwargs['name'])) if with_status: return element, was_created return element
def update_or_create(cls, filter_key=None, **kwargs): """ Update or create the element. If the element exists, update it using the kwargs provided if the provided kwargs are new. Note that when checking kwargs against attributes, only string values are compared. Lists and dicts are automatically merged. If an element does not have a `create` classmethod, then it is considered read-only and the request will be redirected to :meth:`~get`. Provide a ``filter_key`` dict key/value if you want to match the element by a specific attribute and value. If no filter_key is provided, the name field will be used to find the element. :: >>> host = Host('kali') >>> print(host.address) 12.12.12.12 >>> host = Host.update_or_create(name='kali', address='10.10.10.10') >>> print(host, host.address) Host(name=kali) 10.10.10.10 :param dict filter_key: filter key represents the data attribute and value to use to find the element. If none is provided, the name field will be used. :param kwargs: keyword arguments mapping to the elements ``create`` method. :raises CreateElementFailed: could not create element with reason :raises ElementNotFound: if read-only element does not exist :return: element instance by type :rtype: Element """ if not hasattr(cls, 'create'): return cls.get(kwargs.get('name')) elif 'name' not in kwargs: raise ElementNotFound('Name field is a required parameter ' 'for all create type operations on an element') element = None if filter_key: elements = cls.objects.filter(**filter_key) if elements.exists(): element = elements.first() else: try: element = cls.get(kwargs.get('name')) except ElementNotFound: element = None if element: params = {} for key, value in kwargs.items(): value = value() if callable(value) else value val = getattr(element, key, None) if isinstance(val, (string_types, int)): if val != value: params[key] = value else: params[key] = value if params: element.update(**params) else: params = {k: v() if callable(v) else v for k, v in kwargs.items()} element = cls.create(**params) return element