Re: Func Facts and extreme branch is becoming normal

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Friday 13 March 2009 03:50:42 Adrian LIkins wrote:
> makkalot wrote:
> > ********* CAUTION A VERY LONG POST ********************
> >
> > Func Facts :
> >
> > What is it ?
> >   The Facts are modules like minion modules but a little bit different.
> > Facts are like variables of database tables.
> > name,temperature,kernel_version etc. Why to need facts ? The main idea
> > behind facts is to be able to send queries to minions like you do to
> > database or ORM. Example , 'run update method on machines which are f9 >=
> > ... You can do that with current minion modules of course but you have to
> > send at least 2 queries to your minions. Another idea behind fact is to
> > do more things with less connection hits.
> >
> > Python API :
> >   To use Func Facts you can use OverlordQueryProxy (i dont like the name
> > if you have better please tell), as it name says it is a proxy object
> > which acts like
> > Overlord and a little bit more. When writing the facts code i didnt touch
> > the Overlord class because it is already overloaded, and i think that
> > should be the future behaviour of new added bits to func. Keeping
> > Overlord as a little bit abstract may be a good idea. Examples are
> > better:
>
>     Subclassing the Overlord class is probably a good idea. At least for
> the common cases, it wouldn't hurt
> to have some canned subclasses ready to use.
>
>     I'm drawing a blank on better names at the moment

cool.

>
> > #using object as Overlord
> > In [1]: from func.minion.facts.overlord_query import OverlordQueryProxy
> >
> > In [2]: fc = OverlordQueryProxy("*")
> >
> > In [3]: fc.echo.run_string("func blips")
> > Out[3]: {'localhost.localdomain': 'func blips'}
> >
> > #to see the availible fact methods i have written a little minion module
> > to show them ..
> > [root@fedorabig func]# func "*" call fact list_fact_modules
> > {'localhost.localdomain': ['hardware', 'fact_module']}
> >
> > [root@fedorabig func]# func "*" call fact list_fact_methods
> > {'localhost.localdomain': ['hardware.cpu_model',
> >                            'kernel',
> >                            'cpumodel',
> >                            'hardware.kernel_version',
> >                            'cpuvendor',
> >                            'hardware.run_level',
> >                            'hardware.cpu_vendor',
> >                            'hardware.os_name',
> >                            'runlevel',
> >                            'os']}
> >
> > [root@fedorabig func]# func "*" call fact show_fact_module "hardware"
> > {'localhost.localdomain': {'description': 'A modules that supplies
> > hardware facts',
> >                            'name': 'hardware',
> >                            'version': '0.0.1'}}
> >
> >
> > [root@fedorabig func]# func "*" call fact show_fact_method "runlevel"
> > {'localhost.localdomain': {'description': 'Shows the runlevel of the
> > system', 'name': 'runlevel',
> >                            'tag': 'runlevel',
> >                            'usage': 'Can be used with all keywords'}}
>
>     Sounds reasonable API to me, mirrors the normal func module/method
> introspection.

Well i put those just for little demonstration otherwise they are kind of 
useless.

>
> > The facts are methods that mostly (at least now) doesnt accept any
> > arguments, so if you want to see the value of an existing fact just
> >
> > [root@fedorabig func]# func "*" call fact call_fact "runlevel"
> > {'localhost.localdomain': '5'}
>
>     What would be an example of fact methods that need args?

Well i wanted to keep facts as simple as possible, it maybe more useful
if you think about them just as properties of the minion. Can u give me an,
example for sending arguments and why it will be useful. 

>
> > The ORM queries:
> >
> > When Michael mentioned about facts idea i wanted to have something that
> > can let me do some crazy chaining queries so i now i should explain a
> > little bit the query stuff of the facts. With func facts you can run very
> > complex queries. But lets go from easaier to hard :
> >
> > In [3]: fc = OverlordQueryProxy("*")
> > In [6]: result=fc.filter(runlevel=4).echo.run_string("Hey func")  #run
> > that on machine that has runlevel 4
> > In [8]: fc.display_active(result)
> > Out[8]: {}
> >
> > We have no results because my runlevel is different.
> >
> > In [11]: fc = OverlordQueryProxy("*")
> >
> > In [12]:
> > result=fc.filter(runlevel__gt=4,runlevel__lt=6).echo.run_string("Hey
> > func")
> >
> >
> > In [13]: fc.display_active(result)
> > Out[13]: {'localhost.localdomain': 'Hey func'}
> >
> > The query above is for facts that are greater than 4 and less than 5 :)
> > and we have a match
> >
> > Lets do the same thing with async :
> >
> > In [14]: fc = OverlordQueryProxy("*",async=True)
> >
> > In [15]:
> > result=fc.filter(runlevel__gt=4,runlevel__lt=6).echo.run_string("Hey
> > func")
> >
> > In [16]: result
> > Out[16]: '*-echo-run_string-1236893793.6649389'
> >
> > In [17]: fc.job_status(result)
> > Out[17]: (1, {'localhost.localdomain': 'Hey func'})
> >
> > Also you can do chaining when querying like that
> >
> > In [11]: fc = OverlordQueryProxy("*")
> >
> > In [12]: result =
> > fc.filter(runlevel=5).filter(os__icontains="fedora").echo.run_string("Hey
> > func")
> >
> > In [13]: fc.display_active(result)
> > Out[13]: {'localhost.localdomain': 'Hey func'}
>
>     Whats the difference between passing two facts to check to filter,
> and chaining two fact checks together?

No difference wanted to show just the chaining.

>
> > Sometimes you may need some more complex queries by OR'in and 'AND'in the
> > stuff deeply , facts try to support that :
> >
> > In [20]: fc = OverlordQueryProxy("*")
> >
> > In [21]: result = fc.set_complexq(Q(os__icontains="fedora")|
> > Q(os__icontains="ubuntu")).echo.run_string("Hey func")
> >
> > In [23]: fc.display_active(result)
> > Out[23]: {'localhost.localdomain': 'Hey func'}
> >
> > A last example with heavy chaining :)
> >
> > In [24]: fc = OverlordQueryProxy("*")
> >
> > In [25]: result = fc.set_complexq(Q(os__icontains="fedora")|
> > Q(os__icontains="ubuntu")).filter(runlevel=5).echo.run_string("Hey func")
> >
> > In [26]: fc.display_active(result)
> > Out[26]: {'localhost.localdomain': 'Hey func'}
>
>     Not sure what I think about the Q (query? ) api. My first thought is
> that maybe it should just
> be a little domain specific language for that, but thats probably a bad
> idea. The approach you
> take lets you construct the queries a little more programmatically than
> just query strings.
>     What do the filter/queries look like over the wire? (shouldn't
> matter much, just curious)

Well the Q stuff was just an example what u can do programatically using
facts, most of the users wont need them and probably wont know about them.
If you take a look into filter code you will see that under the hood there are 
Q classes. Therefore if you need something like filter_or() method it is very 
easy to add a new one and probably that is the way it should be so the 
statement above will become : 

fc.filter_or(os__icontains="fedora",os__icontains="ubuntu").echo.run_string("Heyfunc")

>
> > Func Keywords :
> >   Func Facts support some keywords that are really useful and makes the
> > world really easy (as you saw above). The "__" is very important when
> > using facts because that is how the things are parsed on other side. For
> > example if you want to have the os that contains name fedora You write
> >
> > fact_method__keyword = some_value --> so os__icontains = "fedora"
> >
> > The current keywords are as follow :
> >   "","gt","gte","lt","lte",'contains','icontains','iexact','startswith'
> >
> > Adding new keywords is pretty easy just go to :
> > func.minion.facts.minion_query.QueryKeyword and add a method in that
> > format def keyword_nameOFyouKeyword(self,overlord_value,fact_value)
> > that is all you need to do.
>
>     Cool.
>
> > Writing Fact Modules:
> >   Fact modules are loaded as almost the same way as minion modules so
> > writing them is also that easy. Go to func.minion.facts.modules and add
> > your module there if there is no problems it should loaded next time you
> > restart your server. IMPORTANT : facts methods doesnt accept currently
> > any arguments, think about
> > them as properties of your system ...
> >
> > Example :
> >
> > class HardwareFacts(fact_module.BaseFactModule):
> >
> >     version = "0.0.1"
> >     description = "A modules that supplies hardware facts"
> >
> >     ##snip snip ..
> >
> >     def run_level(self):
> >         """
> >         The runlevel of the system
> >         """
> >         return str(self.host.defaultRunlevel)
> >
> >     #for easier acces be creful should be unique
> >     run_level.tag = "runlevel"
> >     run_level.description = "Shows the runlevel of the system"
> >     run_level.usage = "Can be used with all keywords"
> >
> > An important thing to note here is the run_level.tag value ,by assigning
> > that value you are able to use your method as tag_value__keyword = blip
> > if you dont assing the "tag" attribute it is ok again just when calling
> > you should do it that way : 	hardware.run_level__keyword = blip
> > Btw, i like the tag idea, be careful not to have 2 tags with same name,
> > the last one will be availible :)
>
>     Hmm, kind of worried about the namespace issues there. Those kind of
> things tend to cause hard
> to find bugs.

It wont be a hard to add a method in minion fact module to 
check_for_duplicates, so when someone add a new fact and has a
duplicate can catch that ?

>
> > For more info you can check the examples ...
> >
> >
> > Under The Hood :
> >   Well how the facts is actually working? What i did was really simle if
> > you use OverlordQueryProxy and used the magical methods like filter and
> > set_complexq , OverlordQueryProxy serializes the current query (ORs and
> > ANDs) and inserts it as an argument to be sent to the minions. The server
> > side (minion)
> > deserializes it executes the logic parts (True and True etc) and if the
> > result is True it continues to executes the actual parts (minion methods)
> > if not returns back to overlord as signing __fact__ as False, so we know
> > that minion doesnt match our query. By doing that we can do lots of thing
> > with one connection or HIT.
>
>     Cool.
>
> > Note :  If you have lots of queries it may useful to run the query
> > "async" you may get timeout.
> >
> >
> > Todo :
> >   -Solving bugs (fixing when writing that post :) )
> >   - Implement it so it can work from commandline, not sure about syntax
> >   - Maybe making Python Api more sweet
>
>     I would like to see the api a little sweeter. Could we do something
> like implement __gt__, __lt__, etc
> on the filter/query objects? We still have a serializing step in the
> middle though. That may require implementing
> minion and overlord versions of the filter/query types though, which
> might make adding types on the fly
> a bit weird though.

Can u give me an example what kind of usage do you think about having 
__gt__, __lt__ ? What will be the benefits ?

>
> Adrian

_______________________________________________
Func-list mailing list
Func-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/func-list

[Index of Archives]     [Fedora Users]     [Linux Networking]     [Fedora Legacy List]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]

  Powered by Linux