****** Module ****** The main purpose of python-appngizer is to offer an easy way to implement python applications to administer and interact with an appNG instance via the appNGizer REST webapplication. To do this entities are represented as :class:`appngizer.elements.Element`. The :attr:`appngizer.elements.Element.xml` attribute helds the XML representation of the entity as an :class:`lxml.objectify.ObjectifiedElement`. The communication is implemented via the :class:`appngizer.client.XMLClient`. By using specific methods of an element corresponding HTTP/S requests are send by the XMLClient (GET for read, POST for create, PUT for update) and returns back the HTTP response which is the usually the new XML representation of the entity. There are also container elements where entities of the same entity type are held. Currently they are only usable for read operations (f.e. read all available Sites) but can be the start point for further improvements like bulk operatios. Read ==== To read an existing appNG entity the :attr:`appngizer.elements.Element.name` attribute is used to identify and access the desired entity. Example ------- Read Site entity ^^^^^^^^^^^^^^^^ .. code-block:: python site = Site('a_site') site.read() print site.dump() .. code-block:: xml a_site http://localhost:8080 test_description true false Create or Update ================ For data manipulating methods like create or update you usually have to deliver all values as kwarg (dictionary is called xdict internally). kwarg are directly mapped to XML components of the entity :attr:`appngizer.elements.Element.xml`. Which kind of XML component (element/s, attribute) an kwarg address is controlled by the first matching key in following class constants of the :class:`appngizer.elements.Element`: - self.FIELDS are entity fields with a simple value (String, Text, Boolean, Integer) - self.ATTRIBUTES are entity attributes with a simple value (String, Text, Boolean, Integer) - self.CHILDS are child entities as SubElements wrapped in a childs element - self.SUBELEMENTS are child entities as SubElements directly under the root element Example ------- Create Site entity ^^^^^^^^^^^^^^^^^^ .. code-block:: python site = Site('a_site') site.create(host='a_site', domain='http://localhost:8080') print site.dump() .. code-block:: xml a_site http://localhost:8080 true false Update Site entity ^^^^^^^^^^^^^^^^^^ .. code-block:: python site = Site('a_site') site.read() site.update(description='test_description', createRepositoryPath=False) print site.dump() .. code-block:: xml a_site http://localhost:8080 test_description true true Site class constants ^^^^^^^^^^^^^^^^^^^^ .. code-block:: python class Site(Element): ''' Class to manage a site ''' FIELDS = OrderedDict() FIELDS['host'] = '' FIELDS['domain'] = '' FIELDS['description'] = '' FIELDS['active'] = True FIELDS['createRepositoryPath'] = False ATTRIBUTES = OrderedDict() ATTRIBUTES['name'] = '' .. warning:: Be aware that renaming of an entity is not possible. Parent entities =============== Some :class:`appngizer.elements.Element` *can* have one or more parent entities. Parent entities are been set by initialising an :class:`appngizer.elements.Element` with a param called *parents* as a list of :class:`appngizer.elements.Element`. Example ------- Read Property entity with parent entity Site ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python site_property = Property('a_site_property', parents=[ Site('a_site') ]) site_property.read() print site_property.dump() .. code-block:: xml test_Value test_defaultValue test_description Read Property entity with parent entity Site and Application ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python site_app_property = Property('a_site_app_property', parents=[ Site('a_site'),Application('an_application') ]) site_app_property.read() print site.dump() .. code-block:: xml test_Value test_defaultValue test_description .. warning:: Be aware that every parent is an ancestor of the preceding parent. So this doesn't work: .. code-block:: python Package('appng-manager', parents=[ Repository('a_special_repo'), Repository('another_repo') ]).install() And as we deal here with lists, order matters, so this also doesn't work: .. code-block:: python Property('a_site_app_property', parents=[ Application('an_application'), Site('a_site') ]).read() Child entities ============== Some :class:`appngizer.elements.Element` can also have one or more child entities. Child entities are also part of the entity XML so we handle them as a :class:`lxml.objectify.ObjectifiedElement` and not like parent entities as :class:`appngizer.elements.Element`. To change child entities you usually use the relevant methods of an :class:`appngizer.elements.Element` with a kwarg where the key match the specific item in self.CHILDS of the :class:`appngizer.elements.Element`. Example ------- Create Subject entity with Groups ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python subj_groups = [] subj_groups.append( Group('Users').xml ) subj_groups.append( Group('Testers').xml ) subj_tester = Subject('a_tester') subj_tester.create(realName='Andy Arbeit', email='andy@aiticon.com', digest='andy1976', groups=subj_groups) subj_tester.read() print subj_tester.dump() .. code-block:: xml Andy Arbeit andy@aiticon.com $2a$13$0wasGmmSdOF6/Kxybist1eSU42Y/n7h7.H3L2cvdasNKVvxHEheX? Europe/Berlin en LOCAL_USER appNG Users group appNG Testers group Subject class constants ^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python class Subject(Element): ''' Class to manage a subject ''' FIELDS = OrderedDict() FIELDS['realName'] = '' FIELDS['email'] = '' FIELDS['description'] = '' FIELDS['digest'] = '' FIELDS['timeZone'] = 'Europe/Berlin' FIELDS['language'] = 'en' FIELDS['type'] = 'LOCAL_USER' CHILDS = OrderedDict() CHILDS['groups'] = None ATTRIBUTES = {'name': ''}