Thursday, December 30, 2010

Running the RHQ agent as root? Alternatives? ACLs!

 

Some RHQ plugins require access to some resources that are normally only readable by root or the respective owner. The example I am using here is the postgres plugin. This plugin needs access to $PGDATA/postgresql.conf in order to show the configuration in the UI (and to possibly update it).

Unfortunately postgres requires this file to be owned by user postgres and only be read(-writable) by this user (mode 600) and the directory containing this file ($PGDATA) is also required to be owned by user postgres and only be accessible by user postgres (mode 700).

 

One way to access the data it to run the RHQ agent as root and be done. But even if the agent does not do any harm, many admins don't feel comfortable with it - especially when using plugins from third parties that they don't have the source for. Or when using the script plugin, which can use shell scripts to do its work.

Luckily there is an easy way to get around this limitation: ACLs

ACL (access control lists) are a posix feature that is implemented in most (all) modern system these days. The way to set and query them are different unfortunately.

On Red HatEnterprise Linux (and Fedora and probably all other Linuxes) you can set them like this ('hrupp' is used as agent user):

postgres$ pwd
/var/db/postgres
postgres$ setfacl -m u:hrupp:rw $PGDATA/postgresql.conf
postgres$ setfactl -m u:hrupp:x $PGDATA

ls shows that there are ACLs enabled:

root# ls -lsa
8 drwx--x---+ 13 postgres postgres 4096 Dec 21 14:04 .
24 -rw-rw----+ 1 postgres postgres 16872 Dec 17 12:11 postgresql.conf

See the little + in the perms? That indicates an active ACL. Those can be queried via getfacl:

root# getfacl .
# file: .
# owner: postgres
# group: postgres
user::rwx
user:hrupp:--x
group::---
mask::--x
other::---

 

root# getfacl postgresql.conf
# file: postgresql.conf
# owner: postgres
# group: postgres
user::rw-
user:hrupp:rw-
group::---
mask::rw-
other::---

Also remember that the mount options need to enable ACLs first.:

root# grep acl /etc/fstab
/dev/mapper/VG_data-data1 /var/db ext4 defaults,acl 1 3

 

On Mac OS X the command to see them in directory listings is 'ls -lea' (shown below). To set an ACL you can use chmod (here 'hrupp' is used as agent user):

postgres$ pwd
/var/db/postgres
postgres$ chmod +a "hrupp allow read,write" postgresql.conf
postgres$ ls -le postgresql.conf
 -rw-------+ 1 postgres  postgres  16759 Jul 22  2009 postgresql.conf
0: user:hrupp allow read,write
postgres$ chmod +a "hrupp allow execute" .
postgres$ ls -lea
drwx------+ 23 postgres  postgres    782 Dec 30 15:00 . 
0: user:hrupp allow search
-rw-------+  1 postgres  postgres  16759 Jul 22  2009 postgresql.conf 
0: user:hrupp allow read,write

The '0:' tells us that this is the first acl on the file. If there were more acls set, they would be enumerated there as well and evaluated in order.

 

I have been told that recent Windows versions also support POSIX ACLs, so this should work there as well.

---

This tip was brought to you by the excellent RHCSA training.

 

Wednesday, December 29, 2010

A pitfall in PendingIntent (with solution)

The Android documentation has a nice overview chapter about how to notifiy the user with status bar notifications.

The example text works quite nicely and the user gets informed and can then call back into the application. But when working on Zwitscher it did not work as intended by me. But lets start slowly.

Setting up a notifiction goes along the lines of (taken from the developer guide):


Intent notificationIntent = new Intent(this, MyClass.class);
PendingIntent contentIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, "Title",
"something went wrong", contentIntent);

where a PendingIntent is set up as a "pointer" and stored by the system so that when the user selects the notification in the status bar the target activity specified in the notificationIntent can be called.

Now sometimes you want to attach some additional data to the intent to be delivered - like a longer explanation why your action failed. You would go like:

Intent notificationIntent = new Intent(context,MyClass.class);
notificationIntent.putExtra("key","value");        
notificationIntent.putExtra("key2",someCounter++);

to add the payload. And in MyClass you would get the data via

Intent intent = getIntent();        
Bundle bundle = intent.getExtras();        
String head = bundle.getString("key");        
Integer body = bundle.getInt("key2");

Now when the notification fires,  the intent is created and attached to the PendingIntent and this shows up in the status bar

User then selects the status bar to see the longer message and presses this area to see the full details. This means that the system delivers "out of the blue" the created Intent message and thus starts MyClass-activity, which then pulls the payload from the intent.

When you do this a few times in a row you will see that the passed counter (someCounter) does increase in your sending activity, but that the receiver always shows the initial value. Canceling the notification in the sender does not help here.

This comes from the fact, that the system does not assume that only because we pass a new Intent object to the pending intent, we want this new intent object to be delivered and just keeps the old (initial) pending intent alive.

To get the desired semantics, we need to pass a flag to tell the system:

PendingIntent pintent = 
PendingIntent.getActivity(context,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);


This flag (FLAG_CANCEL_CURRENT) tells the system that the old pending intent is no longer valid and it should cancel (=remove) it and then create a fresh one for us. There are more possible flags, which are described on the javadoc page for PendingIntent.

 


You can see a full example in the Zwitscher source code on github in the

And remember that Zwitscher is live on the Android market - download and try it :-)

Saturday, December 11, 2010

Zwitscher is on the market

Zwitscher, my Twitter client for Android(*) is now available in the Android-Market.

zwitscher_on_market.png

 

While v0.50 has still rough edges it is what I am basically using as my main and only Twitter client on my mobile. I've completely deleted the official Twitter app :-)

Zwitscher is open source and hosted on GitHub.

Thursday, December 09, 2010

New preview release of RHQ 4 available

 

We have just made a new developer preview release of RHQ available. This release features a lot of changes and improvements in the UI, that is rewritten in GWT.

 

 

Rupp_RHQ_Dashboard.png

Major new features:

  • Improved LDAP support
  • Default dashboard improvements
  • Improved Resource Inventory support
  • Breadcrumbs no longer used
  • I18N
  • New Help section: Docs from the www.rhq-project.org are now available directly through the app.
  • GWT-based user and role edit views finished
  • Metric and Alert template views converted from JSF to GWT
  • Much improved MySQL plugin (by Steve Milidge)

More detailed release notes can be found here: http://rhq-project.org/display/RHQ/Release+Notes+4.0+DP2

Please check out this release and give us as much feedback as you can. Also we are very interested in getting more translations

The release can be downloaded from the link within the release notes

Thanks to everyone who contributed. Heiko (on behalf of the RHQ team)

 

Wednesday, December 08, 2010

I am a RHCSA now :-)

Last week I spend the whole week in the Red Hat training center here in Stuttgart, participating in the Red Hat Certified System Administrator (RHCSA) fast track course and exam. The RHCSA is probably still very unknown and better known under its previous name "RHCT". RHCSA runs on RHEL 6.

The fast track training consists of some more basic aspects of system administration like installing and enabling services, setting up networking in the first half and some more advanced topics like ACLs, SELinux, LVM (with encryption and snapshots) in the second part. The course material works with brand new RHEL 6 stuff and also the exam is on RHEL 6. Top notch!

Friday was exam time. As I am not allowed to talk about this only so far: this is a real-world get things done kind of exam and not some multiple choice test.

And then I was waiting for exam results - and today I got it: I passed and I am now a RHCSA! :-)))

Cert number is 100-003-383

 

Tuesday, December 07, 2010

PGDayEU 2010

I had the big luck to be able to attend the first day of PGDay EU conference here in Stuttgart. Conference was held at the SI-Erlebniszentrum - a location well known to me as the Java Forum Stuttgart took place there for many years.

The conference had around 200 attendees and the main tracks were given in two large rooms. Almost all of the "celebrities" like Simon Riggs, Dave Fetter, Magnus Hagander, Heikki Linnegas, Bruce Momijan (with this son!) were there.

I am not too much a database expert, so talks were very technical to me :) But not non-understandable :-)

One definitively cool talk was given by Gianni Ciolly from 2ndquadrant: he was playing chess against postgres (http://twitpic.com/3dfojr and http://yfrog.com/2q3nq01j). Gianni showed the SQL involved and then played against the DB. The chess figures involved were just done by UTF-8 characters :-)

Bruce Momijan talked about rapid upgrades from 8.x (or even 9.0) to 9.x via the re-written db_upgrade. With it upgrades of a huge database can take as little as 44 seconds (in link mode). Definitively something to have a look at.

After lunch I talked about "Servermonitoring mit RHQ" (in German). I had ~ 40 attendees, which was nice. There definitively was interest and I got some good questions afterwards. I've put my slides online at http://www.pilhuhn.de/hwr/misc/PGDay_EU_2010.pdf . If you want to know more about RHQ, visit http://rhq-project.org.

After attending Simon Riggs' talk about replication, I went to Devrim Gündüz, who was talking about failover using the Red Hat Cluster suite. This talk was very nicely presented with a lot of involvement of the speaker :-)

In the evening EnterpriseDB sponsored a party with food and drinks. There were lots of interesting talks at the tables going on, people all were very nice.

So this PGDay was a very positive experience for me. Unfortunately I could not make it to the 2nd day with more interesting talks.

Saturday, November 20, 2010

Using formatted text (in code) on Android

Putting text into a TextView on Android is easy - you just use TextView.setText(text) unlike other overloaded methods with the same name, you can not just use a String with Html formatting to format the passed text.

In order to do so, you either need to obtain the text from a resource file, use Html.fromHtml(String html) helper method or create a SpannableString that can then be passed to the method.

Html.fromHtml() is actually very convenient:

String s = "This is a <b>fat</b> string";
TextView tv = .. ;
tv.setText(Html.fromHtml(s));

But while working on Zwitscher I saw that Html.fromHtml() is actually very expensive to use, as internally it is using the whole arsenal of XML parsing.

Plan B is using SpannableString...

Creating such a text is a bit complicated as you need to deal with individual Spans and so on, which I found inconvenient.

So I've introduced a SpannableBuilder helper class to make this process easier.

Usage is as follows:

SpannableBuilder builder = new SpannableBuilder(context);
builder.append(status.getRetweetedStatus().getUser().getName(),Typeface.BOLD)      
.appendSpace()
      .append(R.string.resent_by, Typeface.NORMAL)                
      .appendSpace()                
      .append(status.getUser().getName(), Typeface.BOLD);
textView.setText(builder.toString());

Using this helper class does not trigger any XML parsing and is thus a lot faster than Html.fromHtml().

So far only methods that deal with TypeFaces are implemented, but extending the class for modifications of the background would be easy.

Using the camera (from your programs) on Android is easy ...

... if you know how to do it.

If you don't know it, it can be a PITA as I have e.g. described at the Android-Tech-Talk in Stuttgart.

For Zwitscher I was for quite some time trying to enable it to take pictures and upload them to pictures services like with other Twitter clients. So I started looking at the documentation and found a How To entry which basically points to the documentation for the Camera.  So I've been trying around with the preview stuff and was googling like crazy and so on, but this turned out to be too complicated for me to follow in the short term.

Yesterday I was reading about Intents in the Documentation and what Google Intents are available. This brought me to the idea of investigating if the camera could also be called that way.

So I've googled for "android camera app intent" and found this forum post which explains how to do it.

Basically start the camera via:

Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);

and then later when the picture has been taken fetch the picture in the onActivityResult() callback:

@Override
public void onActivityResult(int requestCode, int resultCode,Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==1&& resultCode==RESULT_OK) {
Bitmap bitmap = (Bitmap) data.getExtras().get("data");
}
}

This takes a small picture suitable for e.g. Twitter.

To take a larger picture you need to tell the intent where to store a larger picture and pick it up from that location.

intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, path)

So you see - if you know all this, it is fairly easy to start the camera, take a picture and then use it later. No dealing with PreviewHolder and all that stuff.

 

Thursday, November 04, 2010

Small tip when repeatedly doing upgrade testing

Suppose you want to test upgrading your software from version x to y. This often includes updates of database schemas, tables and content.

The obvious way to do this is

do {
install version x
quit x
install version y
verify upgrade
} while (upgrade was bad)

The install version x step here is usually time consuming and involves UI interactions.

A better approach here is to

install version x
create a db backup
verified = false
while (not verified ) {
install version y
if ( upgrade good )
verified = true
else
install db backup
}

With PostgreSQL taking a backup would look like this:

pg_dump -f outfile -b -C dbname

e.g.:

pg_dump -f ~/jon231.dump -b -C jon231

and then the re-install:

pg_restore outfile

e.g.:

pg_restore ~/jon231.dump

Wednesday, November 03, 2010

Mein erster Android-Vortrag - und wie geht nun es weiter?

Gestern habe ich bei der STUGTUG in Zusammenarbeit mit der JUGS beim Android TechTalk meinen ersten Vortrag zum Thema gehalten.

Ich wurde gefragt, ob ich so über meine ersten Erfahrungen erzählen könne, was ich dann auch gemacht habe - nachdem ich mich an Hand von konkreten Beispielen in eine Materie einarbeiten muss habe ich eben von den Erfahrungen mit meiner ersten App, Zwitscher, berichtet (Folien gibt es hier und hier das Video). Peter Hoffmann hat einen Review geschrieben, wie auch Benny. Alle Videos sind in diesem Album zusammengefasst.

Die Auswertung der Feedback-Bögen gibt ein eher gemischtes Bild. Von "Sehr gut" bis "Kann ich nichts mit anfangen, weil ..."  "... ich nicht weiss was eine Activity ist", "... ich das schon seit Jahren mache" war alles dabei. Der Notendurchschnitt lag bei 2,8.

Mein Fehler war hier offensichtlich, für Anfänger in der Android-Programmierung schon zu tief in der Materie gewesen zu sein, während für die "alten Hasen" nicht so viel Neues dabei war.

Deswegen habe ich mir jetzt mal vorgenommen, möglichst bald einen Workshop für Einsteiger anzubieten, bei dem eine kleine Applikation von Null aus aufgebaut werden soll. Der Workshop wird dabei nicht nur "Frontalunterricht" sein, sondern die Teilnehmer sollen / müssen selbst Hand anlegen (Java SE Kenntnisse müssen vorhanden sein).

Hierzu nun ein paar Fragen:

  • Wird so was (= Einsteiger-Workshop) überhaupt gewünscht?
  • Was ist ein möglicher Zeitrahmen (am Abend, Samstag, Wochenende, Weihnachtsfeiertag, ...)
  • Was darf es kosten? Der Workshop ist non-Profit, aber Räume, WLAN, Getränke und Brötchen / Pizza kosten einfach Geld
  • Was für eine App soll es werden?

Ich habe auch eine Idee für einen umfangreicheren Workshop im Hinterkopf, möchte dazu erst mal noch nichts verraten ;-)

 

 

Tuesday, November 02, 2010

RHQ tab sweep

It has been a while since the last tab sweep, so quite some material has accumulated:

First and notably: we now have contributor guidelines, which should make it easier for everyone to get contributions into RHQ.

Alexander Kiefer has finsihed his master thesis work on the Nagios Plugin and the dynamic types detection. The later work needs to picked up and worked on further. A big part of the resource type (and metric scheduling and .... code depends on the static nature of the metadata in the plugin descriptors. The code is currently in the nagios branch in git.

Anyway: congrats Alex and many thanks for your work and also thanks to your employer, AG der Dillinger Hütten,for sponsoring this work.

Steve Millidge contributed a large overhaul of the MySQL plugin to RHQ - thanks Steve!

The team is currently working on transitioning the UI to GWT for RHQ 4. To see what is going on, you can have a look at a short video overview or play with the first developer preview.

And then there was conference season for me and I gave talks at JUDCon Berlin and 1daytalk Munich:

Mazz has written an interesting article on how to do some RHQ agent profiling via Byteman. He also wrote about remotely installing agents on yet unmanaged machines.

Joseph Marques has written a short article on the new search functionality and a longer analysis on GWT compile performance - this is quite interesting and for sure also helpful for other projects that want to use GWT.

John Sanda has written a whole series of articles on usage of the RHQ cli:

Jay Shaughnessy has also written an article about the RHQ CLI. He is talking about using the provisioning feature from the CLI.

Lukáš Krejčí has also written a series of articles:

 

As always, please give us (and / or the article writers feedback).

Monday, October 18, 2010

Overhauled MySQL plugin for RHQ

I have just pushed a contribution by Steve Millidge to RHQ master. He overhauled the existing MySQL plugin big time, so that it now auto discovers the MySQL server with its databases and users.

Also the number of gathered metrics is vastly improved. The new code is currently only in master (in git), but will also show up in the next RHQ build.

Here is a small screen shot (with the current state of the RHQ 4 UI) that shows what has been discovered on my local MySQL 5.1.51 instance.

 

 

Bildschirmfoto 2010-10-18 um 11.58.06.png

 

As always, try it out and please give us and Steve feedback ( I am sure he also accepts pints as feedback :-)

 

Saturday, October 16, 2010

Android and the title bar progress indicator

 

I just spent quite some time trying to figure out how to get a tiny little spinning progress thingy in the title bar of my application. And to be honest, while there is a lot of documentation out there, it is far from trivial to finally implement it.

The best "how to" is just  few weeks old and the author also wanted to have such a thing.

Basically steps are: define a custom layout for the title bar, ask the system to allow replacing the title bar, set the content layout, only then set the custom title bar layout and then obtain a reference to the ProgressBar object.

As the post above is quite extensive, I just want to emphasis on the latter points:

 

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
   requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); // 1
   setContentView(R.layout.single_tweet);        // 2
   getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
                              R.layout.window_title); // 3
   pg = (ProgressBar) findViewById(R.id.title_progress_bar); // 4

 

Comments for the lines above:

  1. Ask the system to allow for a custom window title
  2. Set the content view of the whole window
  3. set the layout for the custom title
  4. Obtain the reference to the progress bar

If this order is not honored, pg, the reference to the ProgressBar will be null.

The layout for the title is shown in above post, so I'll not repeat it here.

The second important aspect is the usage of the ProgressBar. The main thread of execution in Android is the UI thread. And when a callback is running, the UI is not updating while such a callback is running. So, the following is not starting the progress indicator:

   public void myButtonPressedCallback(View v) {
      pg.setVisibility(ProgressBar.VISIBLE);
      doSomeThingLongRunning();
      pg.setVisibility(ProgressBar.INVISIBLE);
}

The state of the progress indicator will only be set after myButton..() has returned. In oder to correclty handle this, you need to e.g. use an AsyncTask:

 

    private class DownloadImageTask extends AsyncTask<User, Void,Bitmap> {
        protected void onPreExecute() {
            super.onPreExecute();
            pg.setVisibility(ProgressBar.VISIBLE);
        }
        protected Bitmap doInBackground(User... users) {
          doSomeThingLongRunning();
        }
        protected void onPostExecute(Bitmap result) {
           pg.setVisibility(ProgressBar.INVISIBLE);
        }

 

   }

In this case, the ProgressBar is made visible in onPreExecute() (which runs in the UI thread. Then the background thread is started to do the long running computation and after this has finished, onPostExecute() runs again in the UI thread, where you can 'switch off' the ProgressBar again.