"…mais ce serait peut-être l'une des plus grandes opportunités manquées de notre époque si le logiciel libre ne libérait rien d'autre que du code…"

Archive for juillet 2007

Les vues génériques de Django

Posted by patrick sur juillet 20, 2007

Mon apprentissage de Django qui est parti du livre “Restful web services” de Léonard Richardson et Sam Ruby, Copyright 2007, O’Reilly Media, Inc., ISBN-13: 978-0-596-52926-0 m’a fait passer par les méthodes ‘GET’ et ‘POST’ et à cause de cette dernière méthode je suis bien obligé de m’intéresser à l’écriture de pages XHTML qui sont bien la chose la plus longue, pénible et ennuyeuse que l’on puisse imaginer !.

Heureusement, avec Django il y a les vues génériques et un coup de Google m’amène également sur le blog de David Larlet qui a consacré un article à ce sujet bien pénible :). Je vais essayer de détailler un peu plus ce puissant mécanisme.
Voir: -http://www.biologeek.com/journal/index.php/vues-generiques-heritage-et-templatetags-developpez-rapidement-avec-django

http://code.google.com/p/biologeek/(« Suite à la refonte du site, je trouve intéressant de pouvoir mettre les sources à la disposition de tous. Une solution maison à base de Trac pouvait soulever des problèmes pour la pérennité du dépôt alors c’est l’occasion de tester Google Code.Si jamais je regrette ce choix, je pourrais toujours en changer facilement étant donné que ça repose sur Subversion« )

svn checkout http://biologeek.googlecode.com/svn/trunk/ biologeek

Il faut lire également la page http://www.djangoproject.com/documentation/generic_views/ (« Writing Web applications can be monotonous, because we repeat certain patterns again and again. In Django, the most common of these patterns have been abstracted into “generic views” that let you quickly provide common views of an object without actually needing to write any Python code« )

Django’s generic views contain the following:

  • A set of views for doing list/detail interfaces (for example, Django’s documentation index and detail pages).
  • A set of views for year/month/day archive pages and associated detail and “latest” pages (for example, the Django weblog’s year, month, day, detail, and latest pages).
  • A set of views for creating, editing, and deleting objects.

All of these views are used by creating configuration dictionaries in your URLconf files and passing those dictionaries as the third member of the URLconf tuple for a given pattern. For example, here’s the URLconf for the simple weblog app that drives the blog on djangoproject.com:

Pour être plus clair, les vues génériques permettent de ne pas coder de code XHTML ce qui est une très bonne chose :). Le principe est de partir d’un objet défini par son modèle (défini dans /cygdrive/e/projets/pybookmarks/bookmarks/models.py) et de produire une vue générique à partir de ce modèle.

Vues génériques

On peut donc avoir des vues génériques:

  • « Simples »
    • $ python manage.py shell
      Python 2.5.1 (r251:54863, Jun 19 2007, 22:55:07)
      [GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
      Type « help », « copyright », « credits » or « license » for more information.
      (InteractiveConsole)
      >>> from django.views.generic import simple
      >>> dir(simple)
      [‘HttpResponse’, ‘HttpResponseGone’, ‘HttpResponsePermanentRedirect’, ‘RequestContext’, ‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘direct_to_template‘, ‘loader’, ‘redirect_to‘, ‘render_to_response’]
      >>>
    • Exemples issus de biologeek (‘direct_to_template‘) (http://biologeek.googlecode.com/svn/trunk/urls.py)
      • ## Misc
        urlpatterns = patterns('django.views.generic.simple',
            (r'^$',             'direct_to_template', {'template': 'home.html'}),
            (r'^abonnement/$',  'direct_to_template', {'template': 'abonnement.html'}),
            (r'^contact/$',     'direct_to_template', {'template': 'contact.html'}),
            (r'^comments/',     include('django.contrib.comments.urls.comments')),
        )
    • Exemples issus de Django (‘redirect_to‘):
      • This example returns a 410 HTTP error for requests to /bar/:
        urlpatterns = patterns('django.views.generic.simple',
            ('^bar/$', 'redirect_to', {'url': None}),
        )
      • This example redirects from /foo/<id>/ to /bar/<id>/:
        urlpatterns = patterns('django.views.generic.simple',
            ('^foo/(?P<id>d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
        )
    • Exemples issus de Django ('direct_to_template'):
      • urlpatterns = patterns('django.views.generic.simple',
            (r'^foo/$',             'direct_to_template', {'template': 'foo_index.html'}),
            (r'^foo/(?P<id>d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
        )
  • basées sur les dates
    • >>> from django.views.generic import date_based
      >>> dir(date_based)
      [‘DateTimeField’, ‘Http404’, ‘HttpResponse’, ‘ObjectDoesNotExist’, ‘RequestConte
      xt’, ‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘archive_day’, ‘archive_
      index’, ‘archive_month’, ‘archive_today’, ‘archive_week’, ‘archive_year’, ‘datetime’, ‘loader’, ‘object_detail’, ‘populate_xheaders’, ‘time’]
      >>>
    • grâce à la méthode django.views.generic.date_based
  • Liste/détails
    • >>> from django.views.generic import list_detail
      >>> dir(list_detail)
      [‘Http404’, ‘HttpResponse’, ‘InvalidPage’, ‘ObjectDoesNotExist’, ‘ObjectPaginator’, ‘RequestContext’, ‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘loader’, ‘object_detail’, ‘object_list’, ‘populate_xheaders’]
      >>>
  • Creation/Mise à jour
    • >>> from django.views.generic import create_update
      >>> dir(create_update)
      [‘FileField’, ‘Http404’, ‘HttpResponse’, ‘HttpResponseRedirect’, ‘ImproperlyConfigured’, ‘ObjectDoesNotExist’, ‘RequestContext’, ‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘create_object’, ‘delete_object’, ‘loader’, ‘oldforms’, ‘populate_xheaders’, ‘redirect_to_login’, ‘ugettext’, ‘update_object’]
      >>>

A suivre …

Voir:

http://www.djangoproject.com/documentation/newforms/(« django.newforms is Django’s fantastic new form-handling library. It’s a replacement for django.forms, the old form/manipulator/validation framework. This document explains how to use this new library »)

As with the django.forms (“manipulators”) system before it, django.newforms is intended to handle HTML form display, data processing (validation) and redisplay. It’s what you use if you want to perform server-side validation for an HTML form.

For example, if your Web site has a contact form that visitors can use to send you e-mail, you’d use this library to implement the display of the HTML form fields, along with the form validation. Any time you need to use an HTML <form>, you can use this library.

The library deals with these concepts:

  • Widget — A class that corresponds to an HTML form widget, e.g. <input type="text"> or <textarea>. This handles rendering of the widget as HTML.
  • Field — A class that is responsible for doing validation, e.g. an EmailField that makes sure its data is a valid e-mail address.
  • Form — A collection of fields that knows how to validate itself and display itself as HTML.

The library is decoupled from the other Django components, such as the database layer, views and templates. It relies only on Django settings, a couple of django.utils helper functions and Django’s internationalization hooks (but you’re not required to be using internationalization features to use this library).

http://code.djangoproject.com/browser/django/trunk/tests/regressiontests/forms/tests.py

Posted in python, Web applications, xhtml | Leave a Comment »

Une application Web Django (POST)…

Posted by patrick sur juillet 19, 2007

Je poursuis à la fois la lecture du livre ‘RESTful Web Services’ et la lecture du tutorial 4 de django. Lors du billet concernant la méthode HTTP ‘GET’ on a vu que la seule façon d’appeler la méthode ‘POST’ était de passer par un formulaire.

D’abord, je renomme le fichier bookmark/index.html en bookmark/details.html. Je modifie le fichier /cygdrive/e/projets/pybookmarks/bookmarks/views.py en conséquence.

Je mets à jour Django: cd ~/django-src; svn update

$ svn update
U django/conf/locale/sv/LC_MESSAGES/django.po
U django/conf/locale/sv/LC_MESSAGES/django.mo
A django/contrib/localflavor/sk
A django/contrib/localflavor/sk/__init__.py
A django/contrib/localflavor/sk/sk_regions.py
A django/contrib/localflavor/sk/sk_districts.py
A django/contrib/localflavor/sk/forms.py
U tests/regressiontests/forms/localflavor.py
U AUTHORS

Actualisé révision 5724.

Je relance le serveur HTTP: python manage.py runserver

A voir le tutoriel 04 (« This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on simple form processing and cutting down our code« ) et surtout le tutoriel sur les vues génériques de Django (http://www.djangoproject.com/documentation/generic_views/)

Je regarde d’abord ce qui se passe lorsque j’ajoute un objet de type ‘tag’ et que je le modifie à l’aide de l’interface d’administration de django:

Requete POST

[19/Jul/2007 12:11:55] « POST /admin/bookmarks/tag/add/ HTTP/1.1 » 302 0
….
[19/Jul/2007 12:14:08] « POST /admin/bookmarks/tag/4/ HTTP/1.1 » 302 0
[19/Jul/2007 12:14:09] « GET /admin/bookmarks/tag/4/ HTTP/1.1 » 200 2481

Comme on pouvait s’y attendre la requête HTTP ‘POST’ sert aussi bien à la création ‘test’ qu’à la modification ‘test_post’ puisqu’à l’heure actuelle (juillet 2007) les formulaires HTML n’acceptent que des requêtes ‘GET’ ou ‘POST’.

Si on regarde le code XHTML (strict puique voici l’entête du document: <!DOCTYPE html PUBLIC « -//W3C//DTD XHTML 1.0 Strict//EN » « http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd »&gt;) concernant le formulaire voilà ce que l’on a:

<form action="" method="post" id="tag_form">
<div>

   <fieldset class="module aligned ()">

   <div class="form-row" >

    <label for="id_name" class="required">Name:</label>

    <input type="text" id="id_name" class="vTextField required" name="name" size="30" value="test" maxlength="100" />
   </div>

   </fieldset>   <div class="submit-row">

      <p class="float-left"><a href="delete/" class="deletelink">Delete</a></p>

      <input type="submit" value="Save and add another" name="_addanother"  />

      <input type="submit" value="Save and continue editing" name="_continue" />

      <input type="submit" value="Save" class="default" />
   </div>

</div>
</form>

On voit que Django utilise bien les CSS :)(media/css/forms.css) que voici:

/* FORM ROWS */
.form-row { overflow:hidden; padding:8px 12px; font-size:11px; border-bottom:1px solid #eee; }
.form-row img, .form-row input { vertical-align:middle; }
form .form-row p { padding-left:0; font-size:11px; }
/* FORM LABELS */
form h4 { margin:0 !important; padding:0 !important; border:none !important; }
label { font-weight:normal !important; color:#666; font-size:12px; }
label.inline { margin-left:20px; }
.required label, label.required { font-weight:bold !important; color:#333 !important; }
/* MODULES */
.module { border:1px solid #ccc; margin-bottom:5px; background:white; }
.module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left:10px; padding-right:10px; }
.module blockquote { margin-left:12px; }
.module ul, .module ol { margin-left:1.5em; }
.module h3 { margin-top:.6em; }
.module h2, .module caption { margin:0; padding:2px 5px 3px 5px; font-size:11px; text-align:left; font-weight:bold; background:#7CA0C7 url(../img/admin/default-bg.gif) top left repeat-x; color:white; }
.module table { border-collapse: collapse; }
/* FORM DEFAULTS */
input, textarea, select { margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:11px; }
textarea { vertical-align:top !important; }
input[type=text], input[type=password], textarea, select, .vTextField { border:1px solid #ccc; }
.float-right { float:right; }
.float-left { float:left; }
.clear { clear:both; }
.align-left { text-align:left; }
.align-right { text-align:right; }
input[type=submit], input[type=button], .submit-row input { background:white url(../img/admin/nav-bg.gif) bottom repeat-x; padding:3px; color:black; border:1px solid #bbb; border-color:#ddd #aaa #aaa #ddd; }
input[type=submit]:active, input[type=button]:active { background-image:url(../img/admin/nav-bg-reverse.gif); background-position:top; }
input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2; background:#7CA0C7 url(../img/admin/default-bg.gif) bottom repeat-x; font-weight:bold; color:white; }
input[type=submit].default:active { background-image:url(../img/admin/default-bg-reverse.gif); background-position:top; }

 /* ACTION ICONS */
.addlink { padding-left:12px; background:url(../img/admin/icon_addlink.gif) 0 .2em no-repeat; }
.changelink { padding-left:12px; background:url(../img/admin/icon_changelink.gif) 0 .2em no-repeat; }
.deletelink { padding-left:12px; background:url(../img/admin/icon_deletelink.gif) 0 .25em no-repeat; }
a.deletelink:link, a.deletelink:visited { color:#CC3434; }
a.deletelink:hover { color:#993333; }

Bravo pour le côté artistique ! C’est vrai que ça ne s’invente pas. Voilà ce que l’on aurait sans les feuilles de style CSS:

Adlin sans les CSS

Bon ça c’était pour montrer quel travail de Romain il fallait pour saisir simplement un simple champ texte.

Regardons maintenant les vues génériques de Django 

The django.views.generic.create_update module contains a set of functions for creating, editing and deleting objects.

django.views.generic.create_update.create_object

Description:

A page that displays a form for creating an object, redisplaying the form with validation errors (if there are any) and saving the object. This uses the automatic manipulators that come with Django models.

En cours…..

A voir:

http://code.google.com/hosting/search?q=label:django

http://www.djangosites.org/latest/

http://code.google.com/p/django-rest-interface/

http://code.google.com/p/django-restful-model-views/

Posted in python, Web applications | Leave a Comment »

Une application Web Django : le modèle ORM

Posted by patrick sur juillet 18, 2007

Avant d’aborder la méthode HTTP ‘POST‘ je vais regarder rapidement le modèle ORM de Django.

Pourquoi ?

  1. Par simple curiosité 🙂
  2. parce qu’en relisant le tutoriel 01, j’ai vu que l’on pouvait manipuler les objets de la base de données avec une notation objet
  3. parce qu’hier je n’ai pas pu faire ceci dans le fichier bookmarks/template/bookmark/details.html

{% for tag in bookmark.tags %}
<li>{{tag.name}} </li>
{% endfor %}

On a bseoin de la documentation suivante:

http://www.djangoproject.com/documentation/db-api/

http://www.djangoproject.com/documentation/tutorial01/

Sous le répertoire cygwin : /cygdrive/e/projets/pybookmarks on lance la commande suivante:

$ python manage.py shell
Python 2.5.1 (r251:54863, Jun 19 2007, 22:55:07)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type « help », « copyright », « credits » or « license » for more information.
(InteractiveConsole)
>>>

On se retrouve donc sous l’interpréteur Python mais on va voir qu’on a également accès aux objets de la base de données sqlite. Je rappelle le modèle de données utilisé qui est dans le fichier /cygdrive/e/projets/pybookmarks/bookmarks/models.py:

class Tag(models.Model):    name = models.SlugField(maxlength=100)

def __unicode__(self):

return self.name

    class Admin:

pass

class Bookmark(models.Model):

user = models.ForeignKey(User)

url = models.URLField(db_index=True)

short_description = models.CharField(maxlength=255)

long_description = models.TextField(blank=True)

timestamp = models.DateTimeField(default=datetime.datetime.now)

public = models.BooleanField()

tags = models.ManyToManyField(Tag)

def __unicode__(self):

return self.url

class Admin:

pass

Voyons les requêtes que l’on peut faire en ligne de commande.

>>> import datetime
>>> from bookmarks.models import Bookmark, Tag
>>> from django.contrib.auth.models import User

>>> from django.shortcuts import get_object_or_404
>>> dir(Bookmark)
[‘AddManipulator’, ‘ChangeManipulator’, ‘DoesNotExist’, ‘__class__’, ‘__delattr_ _’, ‘__dict__’, ‘__doc__’, ‘__eq__’, ‘__getattribute__’, ‘__hash__’, ‘__init__’, ‘__metaclass__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex_ _’, ‘__repr__’, ‘__setattr__’, ‘__str__’, ‘__unicode__’, ‘__weakref__’, ‘_collec t_sub_objects’, ‘_default_manager’, ‘_get_FIELD_display’, ‘_get_FIELD_filename’, ‘_get_FIELD_height’, ‘_get_FIELD_size’, ‘_get_FIELD_url’, ‘_get_FIELD_width’, ‘ _get_image_dimensions’, ‘_get_next_or_previous_by_FIELD’, ‘_get_next_or_previous _in_order’, ‘_get_pk_val’, ‘_meta’, ‘_prepare’, ‘_save_FIELD_file’, ‘add_to_class’, ‘delete’, ‘get_next_by_timestamp’, ‘get_previous_by_timestamp’, ‘objects‘, ‘ save‘, ‘tags‘, ‘user’, ‘validate’]
>>> Bookmark.objects.all()
[<Bookmark: http://www.python.org&gt;, <Bookmark: http://gump.apache.org/index.html&gt;, <Bookmark: http://www.chomsky.info/&gt;, <Bookmark: http://www.chomsky.info/audi onvideo.htm>, <Bookmark: http://people.csail.mit.edu/meyer/iandc-WWW/Authors/chomskynoam.html>%5D

>>> b = get_object_or_404(Bookmark, pk=3)

>>> dir(b)
[‘AddManipulator’, ‘ChangeManipulator’, ‘DoesNotExist’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__doc__’, ‘__eq__’, ‘__getattribute__’, ‘__hash__’, ‘__init__’, ‘__metaclass__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__str__’, ‘__unicode__’, ‘__weakref__’, ‘_collect_sub_objects’, ‘_default_manager’, ‘_get_FIELD_display’, ‘_get_FIELD_filename’, ‘_get_FIELD_height’, ‘_get_FIELD_size’, ‘_get_FIELD_url’, ‘_get_FIELD_width’, ‘
_get_image_dimensions’, ‘_get_next_or_previous_by_FIELD’, ‘_get_next_or_previous_in_order’, ‘_get_pk_val’, ‘_meta’, ‘_prepare’, ‘_save_FIELD_file’, ‘add_to_class’, ‘delete’, ‘get_next_by_timestamp’, ‘get_previous_by_timestamp’, ‘id’, ‘long_description’, ‘objects’, ‘public’, ‘save’, ‘short_description’, ‘tags’, ‘timestamp’, ‘url’, ‘user’, ‘user_id’, ‘validate’]

>>> b.__metaclass__
<class ‘django.db.models.base.ModelBase’>


>>> b.tags
<django.db.models.fields.related.ManyRelatedManager object at 0x7fc0644c>
>>> dir(b.tags)
[‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__doc__’, ‘__getattribute__’, ‘__hash_, _’, ‘__init__’, ‘__module__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__str__’, ‘__weakref__’, ‘_add_items’, ‘_clear_items’, ‘_pk_val’, ‘_remove_items’, ‘add’, ‘all’, ‘clear’, ‘complex_filter’, ‘contribute_to_class’, ‘core_filters’, ‘count’, ‘create’, ‘creation_counter’, ‘dates’, ‘distinct’, ‘exclude’, ‘extra’, ‘filter’, ‘get’, ‘get_empty_query_set’, ‘get_or_create’,’get_query_set’, ‘in_bulk’, ‘instance’, ‘iterator’, ‘join_table’, ‘latest’, ‘model’, ‘none’, ‘order_by’, ‘remove’, ‘select_related’, ‘source_col_name’, ‘symmetrical’, ‘target_col_name’, ‘values‘]
>>> b.tags.values()
[{‘id’: 2, ‘name’: u’django’}, {‘id’: 3, ‘name’: u’chomsky’}]

OK, c’est ce que je cherchais donc les modifications sont les suivantes:

  • Dans le fichier details.html

{% if mark %}
<ul>
<li> {{mark.url}} </li>
<li> {{mark.user}} </li>
{# <li> {{mark.long_description}} </li> #}
<ul>
{% for tag in tags %}
<li>{{tag.name}} </li>
{% endfor %}
</ul>
</ul>
{% else %}
<p>pas de bookmark.</p>
{% endif %}

  • dans le fichier views.py

c=Context({‘mark’: bookmark,’tags’: bookmark.tags.values()})

Pour information:

– un nouvel ORM python vient de sortir: c’est storm (https://storm.canonical.com/FrontPage)

Lu sur la liste https://lists.ubuntu.com/mailman/listinfo/storm

I’ve started to experiment a little bit exploring whether storm can be used inside of Django. Django has feature to decouple the column names used in the database from the attribute names used when accessing the ORM in python, such as:

class DjangoModel(meta.Model):    bla = IntegerField(db_column="foo")

The equivalent in Storm is:

class MyClass(object):    bla = Int("foo")

Posted in ORM, python | Leave a Comment »

Une application Web Django (GET)…

Posted by patrick sur juillet 17, 2007

Mon précédent billet (http://pvergain.wordpress.com/2007/07/11/restful-resource-oriented-architecture-roa-http-xml/) devenant trop long je continue ici la dernière partie concernant Django.

Le titre du billet est ‘Une application Web Django (GET)...’ . Je n’ai pas mis le terme RESTful car une application Web à l’heure actuelle (juillet 2007) avec les normes HTML4 ou XHTML 1 ne peut utiliser d’autres méthodes HTTP que GET et POST ==> elle n’est donc pas RESTful.

Références pour ce problème méconnu:

  • http://cafe.elharo.com/web/why-rest-failed/ (« The problem is that GET, PUT, POST, and DELETE really are a minimal set. You truly do need all four, and we only have two; and I’ve never understood why. In 2006 browser vendors still don’t support PUT and DELETE. A few browsers over the years have tried to implement these as parts of editing functionality, but they’ve never allowed it in a real web application as opposed to a thick client GUI. The method of an HTML form is limited to GET and POST. PUT and DELETE are not allowed. This isn’t some failure of browser vendors to properly implement the specification either. The HTML specification only allows GET and POST as form actions. XHTML and even XForms 1.0 don’t change this. This means it’s impossible to build a fully RESTful client application inside a web browser. Consequently everyone tunnels everything through POST, and simply ignores PUT and DELETE »)
  • http://www.biologeek.com/journal/index.php/pour-ne-plus-etre-en-rest-comprendre-cette-architecture (« Les applications web utilisent HTTP pour permettre au serveur et au client de communiquer ensemble. … Que se passe-t-il vraiment lorsque vous tapez une adresse dans votre navigateur ? Le navigateur met en forme un message HTTP pour appeler la méthode GET de la ressource identifiée par l’URL que vous lui avez fourni. Vous pouvez aussi appeler la méthode POST à partir de votre navigateur – mais seulement s’il y a un formulaire <form> sur la page. (Ok, pas exactement grâce à AJAX mais oublions pour le moment). Les formulaires peuvent envoyer des données à une URL particulière. Lorsque vous soumettez un formulaire, le navigateur appelle la méthode POST, passant l’URL ainsi que certaines données représentant la ressource qu’il doit ajouter ou modifier. Vous ne pouvez pas appeler PUT ou DELETE avec votre navigateur avec du HTML habituel« )
  • http://groups.google.com/group/django-developers/browse_thread/thread/4278ea1ad73f68f1/e754aa3a5a4fcca2 (« but what is the recommended way to handle fake PUT and DELETE from a browser? The HttpMethodMiddleware ? Maybe a simple form/deletion in the polls application will be an interesting example for a real django case »)
  • http://www.w3.org/TR/html401/interact/forms.html#adef-method (« method = get|post [CI] This attribute specifies which HTTP method will be used to submit the form data set. Possible (case-insensitive) values are « get » (the default) and « post ». See the section on form submission for usage information »)
  • http://www.whatwg.org/specs/web-forms/current-work/#methodAndEnctypes (« The HTTP specification defines various methods that can be used with HTTP URIs. Four of these may be used as values of the method attribute: get, post, put, and delete. In this specification, these method names are applied to other protocols as well. This section defines how they should be interpreted »)

Comme on travaille sur la version de développement, on fait la mise à jour de django (cd ~/django_src; svn update):

pve@pc72 ~/django_src
$ cd ~/django_src; svn update
U django/test/client.py
U django/db/backends/postgresql_psycopg2/introspection.py
U django/conf/locale/de/LC_MESSAGES/djangojs.mo
U django/conf/locale/de/LC_MESSAGES/djangojs.po
U django/conf/locale/es_AR/LC_MESSAGES/django.po
U django/conf/locale/es_AR/LC_MESSAGES/djangojs.mo
U django/conf/locale/es_AR/LC_MESSAGES/django.mo
U django/conf/locale/es_AR/LC_MESSAGES/djangojs.po
U django/conf/locale/fr/LC_MESSAGES/djangojs.mo
U django/conf/locale/fr/LC_MESSAGES/djangojs.po
U django/conf/locale/zh_CN/LC_MESSAGES/django.po
U django/conf/locale/zh_CN/LC_MESSAGES/django.mo
U django/conf/locale/es/LC_MESSAGES/django.po
U django/conf/locale/es/LC_MESSAGES/djangojs.mo
U django/conf/locale/es/LC_MESSAGES/django.mo
U django/conf/locale/es/LC_MESSAGES/djangojs.po
U django/conf/project_template/settings.py
U django/conf/__init__.py
U django/conf/global_settings.py
U django/core/servers/basehttp.py
U django/core/urlresolvers.py
U django/core/validators.py
U django/core/management.py
U django/core/cache/backends/locmem.py
U django/newforms/fields.py
U django/contrib/comments/templatetags/comments.py
U django/contrib/admin/media/js/admin/RelatedObjectLookups.js
U django/contrib/admin/templatetags/admin_list.py
U django/contrib/admin/views/main.py
U django/contrib/localflavor/no/forms.py
U django/contrib/sessions/middleware.py
U django/utils/cache.py
U django/utils/html.py
U django/bin/make-messages.py
U django/template/defaultfilters.py
U django/middleware/common.py
U django/middleware/http.py
U tests/modeltests/str/models.py
U tests/regressiontests/forms/tests.py
U tests/regressiontests/forms/localflavor.py
A tests/regressiontests/utils
A tests/regressiontests/utils/__init__.py
A tests/regressiontests/utils/tests.py
A tests/regressiontests/utils/models.py
U tests/regressiontests/cache/tests.py
U AUTHORS
U docs/db-api.txt
U docs/newforms.txt
U docs/testing.txt
U docs/django-admin.txt
U docs/templates.txt
Updated to revision 5717.

Ensuite, on peut lancer le serveur HTTP django:

$ cd /cygdrive/e/projets/pybookmarks/; python manage.py runserver
Validating models…
0 errors found.

Django version 0.97-pre, using settings ‘pybookmarks.settings’
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

En naviguant sur l’interface d’administration, je m’aperçois qu’il faut installer la bibliothèque docutils (« Docutils is an open-source text processing system for processing plaintext documentation into useful formats, such as HTML or LaTeX. It includes reStructuredText, the easy to read, easy to use, what-you-see-is-what-you-get plaintext markup language« )

Docutils

Je le télécharge au moyen de la commande ‘svn checkout http://svn.berlios.de/svnroot/repos/docutils/trunk/docutils docutils docutils » puis je tape la commande suivante: « cd docutils; python setup.py install »

J’arrête le serveur (Ctrl+C) , je le relance (python manage.py runserver) et cette fois j’ai bien la documentation en ligne à partir du site d’administration.

Docutils

Maintenant on peut continuer à expliquer toutes les lignes du fichier ‘urls.py’: On en est à la partie 3 du tutorial django (This tutorial begins where Tutorial 2 left off. We’re continuing the Web-poll application and will focus on creating the public interface — “views.”, http://www.djangoproject.com/documentation/tutorial03/)

#!/usr/bin/python
# -*- coding: UTF-8 -*-

«  » »
If you need help with regular expressions, see Wikipedis entry
(http://en.wikipedia.org/wiki/Regular_expression)
and the Python documentation. (http://www.python.org/doc/current/lib/module-re.html)
Also, the O’Reilly book Mastering Regular Expression by Jeffrey Friedl is fantastic.

/cygdrive/e/projets/pybookmarks/urls.py
«  » »

from django.conf.urls.defaults import *
from bookmarks.views import *

urlpatterns = patterns( »,
(r’^users/([\w-]+)/$’, bookmark_list),
(r’^users/([\w-]+)/tags/$’, tag_list),
(r’^users/([\w-]+)/tags/([\w-]+)/’, tag_detail),
(r’^users/([\w-]+)/(.+)’, BookmarkDetail()),
(r’^admin/’, include(‘django.contrib.admin.urls’)),
)

L’expression: r’^users/([\w-]+)/$’ est une expression rationnelle (Pour travailler avec les expressions rationnelles, un outil graphique tel que Kodos est vraiment très pratique)

Cette expression identifie une des chaines suivantes

  • users/chomsky
    • Kodos

On l’utilise dans la navigateur Web de cette façon: http://127.0.0.1:8000/users/chomsky

Dans l’exemple du livre ‘RESTful Web Services’ on ne sert pas une page au format HTML mais au format JSON. Je vais donc modifier le fichier ‘ /cygdrive/e/projets/pybookmarks/bookmarks/views.py’ pour servir une page HTML. On étudiera donc les objets django.template (voir http://www.djangoproject.com/documentation/templates, Django’s template language is designed to strike a balance between power and ease. It’s designed to feel comfortable to those used to working with HTML. If you have any exposure to other text-based template languages, such as Smarty or CheetahTemplate, you should feel right at home with Django’s templates.).

Django template

Il faut créer la hiérarchie suivante:

template bookmarks

On crée le fichier template E:/projets/pybookmarks/bookmarks/template/bookmarks/index.html qui contient les lignes suivantes:

{% if latest_bookmark_list %}
<ul>
{% for bookmark in latest_bookmark_list %}
<li>{{ bookmark.url }}</li>
{% endfor %}
</ul>
{% else %}
<p>No bookmarks are available.</p>
{% endif %}

On ajoute les lignes suivantes au fichier views.py:

from django.template import Context, loader

on modifie la fonction « bookmark_list(request, username): »


t=loader.get_template(‘bookmarks/index.html’)
c=Context({‘latest_bookmark_list’: marks})

response = HttpResponse(t.render(c))

On modifie le fichier settings.py:

TEMPLATE_DIRS = (
# Put strings here, like « /home/html/django_templates » or « C:/www/django/templates ».
# Always use forward slashes, even on Windows.
# Don’t forget to use absolute paths, not relative paths.
« E:/projets/pybookmarks/bookmarks/template« ,
)

Et voilà ce que ça donne (j’avais auparavant introduit quelques bookmarks au moyen de l’interface administrateur http://127.0.0.1:8000/admin)

Bookmarks chomsky

Si on regarde le code source de la page on a:

     <ul>

        <li>http://www.chomsky.info/</li>

        <li>http://www.chomsky.info/audionvideo.htm</li>

        <li>http://people.csail.mit.edu/meyer/iandc-WWW/Authors/chomskynoam.html</li>

    </ul>

Ce qui est bien l’instanciation du fichier template E:/projets/pybookmarks/bookmarks/template/bookmarks/index.html

Pour l’instant notre document n’est donc pas du tout conforme aux standards du Web (emploi de XHTML, emploi des feuilles de style CSS, emploi des normes de l’accessibilité du Web). Ce sont des sujets que nous verrons un peu plus tard.

Revenons à notre problème de PUT et DELETE. Dans le fichier /cygdrive/e/projets/pybookmarks/urls.py on a la ligne suivante: (r’^users/([\w-]+)/(.+)’, BookmarkDetail()). Elle permet de lire le détail d’une URL, de détruire une URL ou de créer une URL.

On va d’abord faire un test sur ‘GET’. Je modifie le fichier /cygdrive/e/projets/pybookmarks/bookmarks/views.py pour servir du HTML plutôt que du JSON.

Je modifie la méthode BlogmarkDetail.do_GET():

t=loader.get_template(‘bookmark/index.html’)
c=Context({‘mark’: bookmark,’request’: self.request})
return HttpResponse(t.render(c))

Je crée le fichier ‘bookmark/index.html’:

{% if mark %}
<ul>
<li> {{mark.url}} </li>
<li> {{mark.user}} </li>
<li> {{mark.long_description}} </li>
</ul>
<p> La requete: </p>
<ul>
<li> Request.method={{request.method}}</li>
<li> Request.raw_post_data={{request.raw_post_data}}</li>
</ul>
{% else %}
<p>pas de bookmark.</p>
{% endif %}

Je n’ai pas àmodifier le fichier # /cygdrive/e/projets/pybookmarks/bookmarks/settings.py

Je teste avec l’URL: http://127.0.0.1:8000/users/chomsky/http://www.chomsky.info/ et j’obtiens la page HTML suivante:

Get request

Voilà pour notre premier verbe HTTP: ‘GET’.

Pour ‘POST’ nous devons passer par un formulaire (form) et c’est ce que nous verrons dans le prochain billet en étudiant le tutorial 04 (http://www.djangoproject.com/documentation/tutorial04/, « This tutorial begins where Tutorial 3 left off. We’re continuing the Web-poll application and will focus on simple form processing and cutting down our code »).

Posted in python, REST | Leave a Comment »

RESTful Resource Oriented Architecture (ROA), HTTP, URI, XML

Posted by patrick sur juillet 11, 2007

Analyse du livre « Restful web services » de Léonard Richardson et Sam Ruby, Copyright 2007, O’Reilly Media, Inc., ISBN-13: 978-0-596-52926-0.

Pour les exemples du livre on a besoin de:

– les sources du livre (http://examples.oreilly.com/9780596529260/)

Les sources du livre

– comme je suis au travail sous Windows, j’utilise l’émulateur Cygwin pour avoir un environnement de type UNIX.
– les langages semi-interprétés python, ruby, php et les langage C# et java

– différentes bibliothèques logicielles suivant les langages:

  • la bibliothèque Ruby/Amazon (Attention: « Before you can use this library, you need to obtain an Amazon Web Services developer token« ).
    • Pour l’installer
      • $ ruby setup.rb config
        —> lib
        —> lib/amazon
        —> lib/amazon/search
        —> lib/amazon/search/exchange
        <— lib/amazon/search/exchange
        <— lib/amazon/search
        <— lib/amazon
        <— lib
      • $ ruby setup.rb setup
        —> lib
        —> lib/amazon
        —> lib/amazon/search
        —> lib/amazon/search/exchange
        <— lib/amazon/search/exchange
        <— lib/amazon/search
        <— lib/amazon
        <— lib
      • $ ruby setup.rb install
        —> lib
        mkdir -p /usr/lib/ruby/site_ruby/1.8/
        install amazon.rb /usr/lib/ruby/site_ruby/1.8/
        —> lib/amazon
        mkdir -p /usr/lib/ruby/site_ruby/1.8/amazon
        install search.rb /usr/lib/ruby/site_ruby/1.8/amazon
        install wishlist.rb /usr/lib/ruby/site_ruby/1.8/amazon
        install weddingregistry.rb /usr/lib/ruby/site_ruby/1.8/amazon
        install babyregistry.rb /usr/lib/ruby/site_ruby/1.8/amazon
        install transaction.rb /usr/lib/ruby/site_ruby/1.8/amazon
        install locale.rb /usr/lib/ruby/site_ruby/1.8/amazon
        install shoppingcart.rb /usr/lib/ruby/site_ruby/1.8/amazon
        —> lib/amazon/search
        mkdir -p /usr/lib/ruby/site_ruby/1.8/amazon/search
        install seller.rb /usr/lib/ruby/site_ruby/1.8/amazon/search
        install blended.rb /usr/lib/ruby/site_ruby/1.8/amazon/search
        install exchange.rb /usr/lib/ruby/site_ruby/1.8/amazon/search
        install cache.rb /usr/lib/ruby/site_ruby/1.8/amazon/search
        —> lib/amazon/search/exchange
        mkdir -p /usr/lib/ruby/site_ruby/1.8/amazon/search/exchange
        install marketplace.rb /usr/lib/ruby/site_ruby/1.8/amazon/search/exchange
        install thirdparty.rb /usr/lib/ruby/site_ruby/1.8/amazon/search/exchange
        <— lib/amazon/search/exchange
        <— lib/amazon/search
        <— lib/amazon
        <— lib
  • la commande s3sh pour Ruby (http://amazon.rubyforge.org/ , AWS::S3 A Ruby Library for Amazon’s Simple Storage Service’s (S3) REST API).
    • pve@pc72 /cygdrive/e/Temp/rubygems-0.9.4/rubygems-0.9.4
      $ gem i aws-s3 -ry
      Bulk updating Gem source index for: http://gems.rubyforge.org
      Successfully installed aws-s3-0.4.0
      Successfully installed xml-simple-1.0.11
      Successfully installed builder-2.1.2
      Successfully installed mime-types-1.15
      Installing ri documentation for aws-s3-0.4.0…
      Installing ri documentation for builder-2.1.2…
      Installing ri documentation for mime-types-1.15…
      Installing RDoc documentation for aws-s3-0.4.0…
      Installing RDoc documentation for builder-2.1.2…
      Installing RDoc documentation for mime-types-1.15…
      pve@pc72 /cygdrive/e/Temp/rubygems-0.9.4/rubygems-0.9.4

Test du premier programme ruby:

#!/usr/bin/ruby -w
# amazon-book-search.rb
require ‘amazon/search’

if ARGV.size != 2
puts « Usage: #{$0} [Amazon Web Services AccessKey ID] [text to search for] »
exit
end
access_key, search_request = ARGV

req = Amazon::Search::Request.new(access_key)
# For every book in the search results…
req.keyword_search(search_request, ‘books’, Amazon::Search::LIGHT) do |book|
# Print the book’s name and the list of authors.
puts %{« #{book.product_name} » by #{book.authors.join(‘, ‘)}}
end

  • $ ruby amazon-book-search.rb 126116STACCESSID « restful web services »
    « RESTful Web Services » by Leonard Richardson, Sam Ruby, David Heinemeier Hansson

Bon j’ai détaillé ce premier exemple car je n’avais encore jamais travaillé avec Ruby. Donc quittons cet aspect très pratique pour entrer dans l’aspect plus théorique du livre.

Les auteurs introduisent la notion de « Web programmable » qui est basée sur d’abord et avant tout sur le protocole HTTP et XML (éventuellement HTML, JSON, du texte et du binaire). « If you don’t use HTTP, you’re not on the web« . Il y a donc tout un paragraphe (« HTTP: Documents in Envelopes ») sur HTTP. On y apprend que à part les méthodes GET et POST que tout le monde connait 🙂 il y a les méthodes beaucoup plus méconnues que sont HEAD, PUT et DELETE sans compter OPTIONS, TRACE et CONNECT. La méthode ‘GET’ permet de rechercher une ressource, la commande ‘DELETE’ permet de la détruire tandis que la commande ‘PUT’ permet de la mettre à jour.

On en vient à l’exemple de recherche de photos sur flickr (http://www.flickr.com/services/api/keys/apply. On sait qu’on fait une recherche de ressources grâce à l’emploi du nom de la méthode ‘flickr.photos.search’ qui fait référence à la méthode HTTP GET.

Il y a une comparaison entre les 2 URIS équivalentes suivantes:

http://flickr.com/photos/tags/penguin –> la méthode est ‘GET’ et l’information de portée (scoping information) est ‘les photos taggés penguin’

-http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=xxx&tags=penguin (dans le bouquin ils ont oublié de mettre &api_key=xxx) –> la méthode est ‘recherche une photo’ et l’information de portée est ‘penguin’.

Il n’y a pas de différence technique entre les 2 URIs mais il y a une différence au niveau de l’architecture si on emploie une méthode comme ‘flickr.photos.delete’ qui utilisera la méthode HTTP GET à une place qui ne lui était pas destinée (‘into places it wasn’t meant to go’). On a une architecture REST-RPC hybride (p.16)

A partir de là (« RESTful, Resource-Oriented Architectures(ROA), page 13), les auteurs définissent ce qu’ils entendent par de véritables services web Restful: ce sont des services qui resemblent au web et ils les appellent ‘Orientés ressource’ (resource oriented’).

Dans des architectures RESTful ‘Orientées Ressource’ l’information de portée est dans l’URI et l’architecture est RESTful car la méthode d’information est la méthode HTTP. Si l’information de portée (scoping information) n’est pas dans l’URI alors le service n’est pas ‘Orienté Ressource’.

Les services suivants sont considérés comme étant ‘RESTFul, orientés ressource‘:

tandis que les suivants sont considérés comme REST-RPC hybrid:

  • l’API del.icio.us
  • l’API « REST » de flickr
  • la plupart des applications web

Fin du chapitre 1 (ch1)

Dans le chapitre 2 (« Writing Web Service Clients ») on confirme que l’API del.icio.us n’utilise que la méthode HTTP ‘GET’ quel que soit le service demandé ! Le chapitre 7 « A service implementation » montrera ce qu’est un service RESTful pour le service del.icio.us.

Le but de ce chapitre est d’écrire des clients del.icio.us à l’aide de différents langages et d’utiliser en conséquence différentes bibliothèques permettant de faire des requêtes HTTP. Ces bibliothèques doivent respecter ces caractéristiques:

– le support de HTTPS et du certificat SSL

– implémenter au moins les 5 méthodes HTTP suivantes: GET, HEAD, POST, PUT et DELETE. On rappelle que malheureusement certaines bibliothèques ne supportent que GET et POST et parfois même uniquement GET ! Les méthodes comme OPTIONS , TRACE et la méthode MOVE du protocole Webdav sont un bonus.

– doit permettre au programmeur de manipuler les données envoyées lors d’une requête PUT ou POST

– doit permettre au programmeur de modifier les headers HTTP

– doit donner au programmeur au code retour et aux headers HTTP de la réponse

– doit pouvoir communiquer au travers d’un serveur mandataire HTTP.

– etc.

La bibliothèque standard de Ruby (open-uri) ne supporte que la méthode ‘GET’. Sam Ruby a écrit rest-open-uri

$ gem install rest-open-uri
Successfully installed rest-open-uri-1.0.0
Installing ri documentation for rest-open-uri-1.0.0…
Installing RDoc documentation for rest-open-uri-1.0.0…

Pour Python, il y a urllib2 (semblable à open-uri), httplib et l’excellente bibliothèque de Joe Gregorio httplib2 (http://bitworking.org/projects/httplib2) supportant pratiquement toutes les caractéristiques d’une bonne bibliothèqueHTTP.

pve@pc72 /cygdrive/e/Temp/httplib2-0.3.0
$ python setup.py install
running install
running build
running build_py
creating build
creating build/lib
creating build/lib/httplib2
copying httplib2/__init__.py -> build/lib/httplib2
copying httplib2/iri2uri.py -> build/lib/httplib2
running install_lib
creating /usr/lib/python2.5/site-packages/httplib2
running install_egg_info
Writing /usr/lib/python2.5/site-packages/httplib2-0.3.0-py2.5.egg-info

Je passe sur Java et C#. Pour PHP, il y a libcurl; pour Javascript XMLHttpRequest (voir chapitre 11).

En ligne de commande on a cURL (http://curl.haxx.se) qui est livré en standard sous cygwin. Utiliser l’option -v de cURL permet d’avoir des informations très intéressantes.

Pour info: lynx est aussi un outil intéressant pour les apllications web.
On passe ensuite aux parsers XML

– Ruby: REXML(interfaces DOM et SAX, support XPath). Attention: ne rejette pas le XML mal formé. Autres bibliohèques: libxml2 du projet GNOME, hpricot

$ gem install hpricot
Select which gem to install for your platform (i386-cygwin)
1. hpricot 0.6 (mswin32)
2. hpricot 0.6 (jruby)
3. hpricot 0.6 (ruby)
4. hpricot 0.5 (ruby)
5. hpricot 0.5 (mswin32)
6. Skip this gem
7. Cancel installation
> 3
Building native extensions. This could take a while…
Successfully installed hpricot-0.6
Installing ri documentation for hpricot-0.6…
Installing RDoc documentation for hpricot-0.6…

– Python: ElementTree (support XPath limité), 4Suite (support complet de XPath, http://4suite.org), …etc.

Pour le format JSON, voir le site http://www.json.org.

On finit le chapitre par WADL. Voir le site http://tomayac.de/rest-describe/latest/RestDescribe.html.

Fin du chapitre 2.

Chapitre 3, « What makes Restful services different ? »

Les auteurs rappellent que les APIs del.icio.us et Flickr marchent comme le web lorsqu’il s’agit de rechercher des données mais que ce sont des services de style RPC lorsqu’il s’agit de modifier des données. Les différents services de recherche Yahoo! sont très RESTful mais ils sont si simples qu’il ne peuvent servir d’exemples. Par contre le protocole de publication Atom (APP) et le service de stockage simple d’Amazon (S3) décrit dans ce chapitre sont RESTful et orientés ressources. Amazon fournit des biblothèques d’accès à ce service pour différents langages et outils (comme cURL) (http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=47)

Le service S3 RESTful expose toutes les fonctionnalités du service style RPC mais au lieu de le faire avec des noms de fonction spécialisées il expose des objets standards HTTP appelés ‘ressources‘. Au lieu de répondre à des noms de fonctions comme ‘getObjects’ une ressource répond à une ou plusieurs des 4 méthodes HTTP standards: GET, HEAD, PUT et DELETE.

– Pour avoir la valeur d’un objet on envoie la requête ‘GET’ sur l’URI de cet objet

– pour obtenir uniquement les métadonnées de cet objet on envoie la requête ‘HEAD’ sur la même URI

– pour créer un ‘bucket’, on envoie la requête ‘PUT’ sur l’URI de l’objet contenant le nom du bucket

– pour détruire un ‘bucket’ ou un autre objet, on envoie la requête ‘DELETE’ sur l’URI correspondante.

Les concepteurs de S3 n’ont rien fait d’extraordinaire. Suivant le standard HTTP c’est pour faire ce genre de choses que les méthodes GET, HEAD, PUT et DELETE ont été créées !

Les codes de réponse HTTP pour S3 vont de 200 (« OK »), 404 (« NotFound »). La plus commune est 403 (« Forbidden »). S3 utilise aussi les codes 400 (« Bad request ») indiquant que le serveur ne comprend pas les données envoyées par le client, 409 (« Conflict ») envoyé au client qui essaye de détruire un bucket qui n’est pas vide.

Ensuite on crée une bibliothèque Ruby pour impléménter un client S3. Le but est d’illustrer la théorie derrière REST. Au lieu d’utiliser des noms de méthodes spécifiques, on utilisera des noms qui reflèteront l’architecture RESTful: get, put, delete etc… Les auteurs créent un module nommé S3::Authorized dans le fichier S3lib.rb qu’il faut modifier pour entrer sa clé publique et sa clé privée (« Enter your public key (Amazon calls it an « Access Key ID ») and your private key (Amazon calls it a « Secret Access Key ». This is so you can sign your S3 requests and Amazon will know who to charge »)

Je vérifie avec curl la validité de mes clés.

pve@pc72 ~
$ cat > pubkey.txt <<EOF
> 1261ffffffffff8X19802
> EOF

pve@pc72 ~
$ cat > key.txt <<EOF
> tmaTMgnMiyyyyyyyyyyypMCV8O9JdxQ4
> EOF
$ curl -v –key key.txt –pubkey pubkey.txt https://s3.amazonaws.com/
* About to connect() to s3.amazonaws.com port 443 (#0)
* Trying 72.21.203.129… connected
* Connected to s3.amazonaws.com (72.21.203.129) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: /usr/share/curl/curl-ca-bundle.crt
CApath: none
* SSLv2, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using RC4-MD5
* Server certificate:
* subject: /C=US/ST=Washington/L=Seattle/O=Amazon.com Inc./CN=s3.amazonaw
s.com
* start date: 2007-02-20 00:00:00 GMT
* expire date: 2008-02-20 23:59:59 GMT
* common name: s3.amazonaws.com (matched)
* issuer: /C=US/O=RSA Data Security, Inc./OU=Secure Server Certification
Authority
* SSL certificate verify ok.
> GET / HTTP/1.1
> User-Agent: curl/7.16.3 (i686-pc-cygwin) libcurl/7.16.3 OpenSSL/0.9.8e zlib/1.
2.3 libssh2/0.15-CVS
> Host: s3.amazonaws.com
> Accept: */*
>
< HTTP/1.1 307 Temporary Redirect
< x-amz-id-2: PyFBRRXn6ohqSTY/OdVyE54dsts1bEsUPYluggqw67RWYEhGBrDl3Ru55piRhIgf
< x-amz-request-id: 4546F4FDF40D80AF
< Date: Wed, 11 Jul 2007 10:27:39 GMT
< Location: http://aws.amazon.com/s3
< Content-Length: 0
< Server: AmazonS3
<
* Connection #0 to host s3.amazonaws.com left intact
* Closing connection #0
* SSLv3, TLS alert, Client hello (1):

J’ai un problème avec le client ruby:

pve@pc72 /cygdrive/e/projets/REST/ruby/ch3
$ ruby s3-sample-client.rb buck1 obj1 5
/usr/lib/ruby/1.8/net/http.rb:567: warning: using default DH parameters.
/usr/lib/ruby/gems/1.8/gems/rest-open-uri-1.0.0/lib/rest-open-uri.rb:320
n_http’: 403 Forbidden (OpenURI::HTTPError)
from /usr/lib/ruby/gems/1.8/gems/rest-open-uri-1.0.0/lib/rest-op
b:659:in `buffer_open’
……
b:162:in `open_uri’
from /usr/lib/ruby/gems/1.8/gems/rest-open-uri-1.0.0/lib/rest-op
b:561:in `open’
from /usr/lib/ruby/gems/1.8/gems/rest-open-uri-1.0.0/lib/rest-op
b:35:in `open’
from ./S3lib.rb:276:in `open’
from ./S3lib.rb:45:in `get’
from s3-sample-client.rb:13

Ensuite on a un exemple d’utilisation de Ruby on rails pour la création de services RESTful. On installe donc Ruby on rails avec la commande ‘gem install rails’

$ gem install rails
Need to update 13 gems from http://gems.rubyforge.org
………….
complete
Install required dependency rake? [Yn] Y
Install required dependency activesupport? [Yn] Y
Install required dependency activerecord? [Yn] Y
Install required dependency actionpack? [Yn] Y
Install required dependency actionmailer? [Yn] Y
Install required dependency actionwebservice? [Yn] Y
Successfully installed rails-1.2.3
Successfully installed rake-0.7.3
Successfully installed activesupport-1.4.2
Successfully installed activerecord-1.15.3
Successfully installed actionpack-1.13.3
Successfully installed actionmailer-1.3.3
Successfully installed actionwebservice-1.2.3
Installing ri documentation for rake-0.7.3…
Installing ri documentation for activesupport-1.4.2…
Installing ri documentation for activerecord-1.15.3…
Installing ri documentation for actionpack-1.13.3…
Installing ri documentation for actionmailer-1.3.3…
Installing ri documentation for actionwebservice-1.2.3..
Installing RDoc documentation for rake-0.7.3…
Installing RDoc documentation for activesupport-1.4.2…
Installing RDoc documentation for activerecord-1.15.3…
Installing RDoc documentation for actionpack-1.13.3…
Installing RDoc documentation for actionmailer-1.3.3…
Installing RDoc documentation for actionwebservice-1.2.3

pve@pc72 /cygdrive/e/projets/REST/ruby/ch3

On apprend que:

– dans une application Rails, le modèle et le contrôleur du modèle MVC peuvent se comporter comme un service web RESTful. L’interface d’ActiveResource est analogue à l’interface d’ActiveRecord: avec ActiveRecord les objets sont dans une base de données et sont exposés au moyen de SQL avec les commandes SELECT, INSERT, UPDATE et DELETE. Avec ActiveResource ils sont au sein d’une application Rails, exposés au moyen de HTTP avec les commandes GET, POST, PUT et DELETE.

En conclusion, un clone de S3 en Ruby : http://code.whytheluckystiff.net/parkplace

Chapitre 4: The Resource-Oriented Architecture (ROA)

L’architecture ROA est une façon de transformer un problème en service web RESTful: un ensemble d’URIs, d’HTTP et de XML qui marchent comme le reste du web et que les programmeurs aimeront 🙂

Les services Web RESTful peuvent être classés suivant les réponses à 2 questions:

– l’information de portée est stockée dans l’URI : (pourquoi le serveur enverrait cette information plutôt qu’une autre ?) C’est le principe d’adressabilité.

– la méthode d’information est la méthode HTTP (pourquoi le serveur devrait-il envoyer cette donnée au lieu de la détruire ?)

Pour les auteurs, REST n’est pas une architecture (ce qui est en contradiction avec la définition donnée par Wikipedia) mais un ensemble de critères de conception. Je ne vais pas plus loin dans leur définition car elle est en contradiction totale de ce que je lis sur Wikipedia. Les auteurs estiment que REST n’a pas de rapport direct avec HTTP et les URIs.

Quelques définitions:

– à une ressource doit correpondre au moins une URI. L’URI est le nom et l’adresse de la ressource. Je fais remarquer que le U dans URI veut dire Uniform et non Universal et ce depuis décembre 1994 (voir http://tools.ietf.org/html/rfc1738)

– une URI devrait être descriptive et avoir une structure (c’est donc une convention à adopter)

– 2 ressources ne peuvent avoir la même URI

– une ressource peut avoir 1 ou plusieurs URI

– une URI désigne par définition une et une seule ressource

– une application est adressable si elle expose ses données en tant que ressources

– le fait d’avoir une URI pour chaque ressource permet l’utilisation de mandataires HTTP (proxies HTTP) pour la mise en cache des ressources

– une requête HTTP est sans état (statelessness)

– une ressource est une source de représentations multiples

– pour désigner des représentations différentes les auteurs recommandent de leur attribuer une URI distincte. Exemple: ajouter un .es, .en, .fr suivant la langue. Une alternative est la négociation du contenu (content negociation, voir les champs HTTP header: Accept-Language et Accept).

Ici les auteurs abordent la notion d’interface uniforme:

– pour lire une ressource on utilise la requête ‘GET

   The GET method means retrieve whatever information (in the form of an
   entity) is identified by the Request-URI. If the Request-URI refers
   to a data-producing process, it is the produced data which shall be
   returned as the entity in the response and not the source text of the
   process, unless that text happens to be the output of the process.

   The semantics of the GET method change to a "conditional GET" if the
   request message includes an If-Modified-Since, If-Unmodified-Since,
   If-Match, If-None-Match, or If-Range header field. A conditional GET
   method requests that the entity be transferred only under the
   circumstances described by the conditional header field(s). The
   conditional GET method is intended to reduce unnecessary network
   usage by allowing cached entities to be refreshed without requiring
   multiple requests or transferring data already held by the client.

   The semantics of the GET method change to a "partial GET" if the
   request message includes a Range header field. A partial GET requests
   that only part of the entity be transferred, as described in section
   14.35. The partial GET method is intended to reduce unnecessary
   network usage by allowing partially-retrieved entities to be
   completed without transferring data already held by the client.

   The response to a GET request is cacheable if and only if it meets
   the requirements for HTTP caching described in section 13

– pour supprimer une ressource on utilise la requête ‘DELETE’

   The DELETE method requests that the origin server delete the resource
   identified by the Request-URI. This method MAY be overridden by human
   intervention (or other means) on the origin server. The client cannot
   be guaranteed that the operation has been carried out, even if the
   status code returned from the origin server indicates that the action
   has been completed successfully. However, the server SHOULD NOT
   indicate success unless, at the time the response is given, it
   intends to delete the resource or move it to an inaccessible
   location.

   A successful response SHOULD be 200 (OK) if the response includes an
   entity describing the status, 202 (Accepted) if the action has not
   yet been enacted, or 204 (No Content) if the action has been enacted
   but the response does not include an entity.

   If the request passes through a cache and the Request-URI identifies
   one or more currently cached entities, those entries SHOULD be
   treated as stale. Responses to this method are not cacheable.

– pour créer ou modifier une ressource utiliser la requête ‘PUT‘ associée à l’URI

   The PUT method requests that the enclosed entity be stored under the
   supplied Request-URI. If the Request-URI refers to an already
   existing resource, the enclosed entity SHOULD be considered as a
   modified version of the one residing on the origin server. If the
   Request-URI does not point to an existing resource, and that URI is
   capable of being defined as a new resource by the requesting user
   agent, the origin server can create the resource with that URI. If a
   new resource is created, the origin server MUST inform the user agent
   via the 201 (Created) response. If an existing resource is modified,
   either the 200 (OK) or 204 (No Content) response codes SHOULD be sent
   to indicate successful completion of the request. If the resource
   could not be created or modified with the Request-URI, an appropriate
   error response SHOULD be given that reflects the nature of the
   problem. The recipient of the entity MUST NOT ignore any Content-*
   (e.g. Content-Range) headers that it does not understand or implement
   and MUST return a 501 (Not Implemented) response in such cases.

   If the request passes through a cache and the Request-URI identifies
   one or more currently cached entities, those entries SHOULD be
   treated as stale. Responses to this method are not cacheable.

   The fundamental difference between the POST and PUT requests is
   reflected in the different meaning of the Request-URI. The URI in a
   POST request identifies the resource that will handle the enclosed
   entity. That resource might be a data-accepting process, a gateway to
   some other protocol, or a separate entity that accepts annotations.
   In contrast, the URI in a PUT request identifies the entity enclosed
   with the request -- the user agent knows what URI is intended and the
   server MUST NOT attempt to apply the request to some other resource.
   If the server desires that the request be applied to a different URI,

Fielding, et al.            Standards Track                    [Page 55]
 
RFC 2616                        HTTP/1.1                       June 1999

   it MUST send a 301 (Moved Permanently) response; the user agent MAY
   then make its own decision regarding whether or not to redirect the
   request.

   A single resource MAY be identified by many different URIs. For
   example, an article might have a URI for identifying "the current
   version" which is separate from the URI identifying each particular
   version. In this case, a PUT request on a general URI might result in
   several other URIs being defined by the origin server.

   HTTP/1.1 does not define how a PUT method affects the state of an
   origin server.

– pour retrouver les métadata d’une ressource utiliser la requête ‘HEAD‘. Un client peut utiliser cette requête pour voir si une requête existe.

   The HEAD method is identical to GET except that the server MUST NOT
   return a message-body in the response. The metainformation contained
   in the HTTP headers in response to a HEAD request SHOULD be identical
   to the information sent in response to a GET request. This method can
   be used for obtaining metainformation about the entity implied by the
   request without transferring the entity-body itself. This method is
   often used for testing hypertext links for validity, accessibility,
   and recent modification.

   The response to a HEAD request MAY be cacheable in the sense that the
   information contained in the response MAY be used to update a
   previously cached entity from that resource. If the new field values
   indicate that the cached entity differs from the current entity (as
   would be indicated by a change in Content-Length, Content-MD5, ETag
   or Last-Modified), then the cache MUST treat the cache entry as
   stale.

– pour savoir quelles opérations sont permises sur une ressource employer la requête ‘OPTIONS‘. Bon c’est de la théorie puisque très peu de serveurs offrent ce support.

   The OPTIONS method represents a request for information about the
   communication options available on the request/response chain
   identified by the Request-URI. This method allows the client to
   determine the options and/or requirements associated with a resource,
   or the capabilities of a server, without implying a resource action
   or initiating a resource retrieval.

   Responses to this method are not cacheable.

   If the OPTIONS request includes an entity-body (as indicated by the
   presence of Content-Length or Transfer-Encoding), then the media type
   MUST be indicated by a Content-Type field. Although this
   specification does not define any use for such a body, future
   extensions to HTTP might use the OPTIONS body to make more detailed
   queries on the server. A server that does not support such an
   extension MAY discard the request body.

   If the Request-URI is an asterisk ("*"), the OPTIONS request is
   intended to apply to the server in general rather than to a specific
   resource. Since a server's communication options typically depend on
   the resource, the "*" request is only useful as a "ping" or "no-op"
   type of method; it does nothing beyond allowing the client to test
   the capabilities of the server. For example, this can be used to test
   a proxy for HTTP/1.1 compliance (or lack thereof).

   If the Request-URI is not an asterisk, the OPTIONS request applies
   only to the options that are available when communicating with that
   resource.

   A 200 response SHOULD include any header fields that indicate
   optional features implemented by the server and applicable to that
   resource (e.g., Allow), possibly including extensions not defined by
   this specification. The response body, if any, SHOULD also include
   information about the communication options. The format for such a

Fielding, et al.            Standards Track                    [Page 52]
 
RFC 2616                        HTTP/1.1                       June 1999

   body is not defined by this specification, but might be defined by
   future extensions to HTTP. Content negotiation MAY be used to select
   the appropriate response format. If no response body is included, the
   response MUST include a Content-Length field with a field-value of
   "0".

   The Max-Forwards request-header field MAY be used to target a
   specific proxy in the request chain. When a proxy receives an OPTIONS
   request on an absoluteURI for which request forwarding is permitted,
   the proxy MUST check for a Max-Forwards field. If the Max-Forwards
   field-value is zero ("0"), the proxy MUST NOT forward the message;
   instead, the proxy SHOULD respond with its own communication options.
   If the Max-Forwards field-value is an integer greater than zero, the
   proxy MUST decrement the field-value when it forwards the request. If
   no Max-Forwards field is present in the request, then the forwarded
   request MUST NOT include a Max-Forwards field.

– la requête HTTP ‘POST‘ est la plus mal comprise des méthodes HTTP:

   The POST method is used to request that the origin server accept the
   entity enclosed in the request as a new subordinate of the resource
   identified by the Request-URI in the Request-Line. POST is designed
   to allow a uniform method to cover the following functions:

      - Annotation of existing resources;

      - Posting a message to a bulletin board, newsgroup, mailing list,
        or similar group of articles;

      - Providing a block of data, such as the result of submitting a
        form, to a data-handling process;

      - Extending a database through an append operation.

   The actual function performed by the POST method is determined by the
   server and is usually dependent on the Request-URI. The posted entity
   is subordinate to that URI in the same way that a file is subordinate
   to a directory containing it, a news article is subordinate to a
   newsgroup to which it is posted, or a record is subordinate to a
   database.

   The action performed by the POST method might not result in a
   resource that can be identified by a URI. In this case, either 200
   (OK) or 204 (No Content) is the appropriate response status,
   depending on whether or not the response includes an entity that
   describes the result.

Fielding, et al.            Standards Track                    [Page 54]
 
RFC 2616                        HTTP/1.1                       June 1999

   If a resource has been created on the origin server, the response
   SHOULD be 201 (Created) and contain an entity which describes the
   status of the request and refers to the new resource, and a Location
   header (see section 14.30).

   Responses to this method are not cacheable, unless the response
   includes appropriate Cache-Control or Expires header fields. However,
   the 303 (See Other) response can be used to direct the user agent to
   retrieve a cacheable resource.

Dans une conception RESTful, la méthode ‘POST’ signifie ‘ajouter’ (append) une ressource à une ressource existante. La différence entre ‘PUT’ et ‘POST’ est la suivante: le client utilise la méthode ‘PUT’ lorsque c’est le client qui décide de l’URI de la ressource; le client utilise la méthode ‘POST’ lorsque c’est le serveur qui décide de l’URI qui identifiera la nouvelle ressource. Autrement dit la méthode ‘POST est une façon de créer une nouvelle ressource sans que le client ait la connaissance exacte de sa future URI. Dans la plupart des cas, le client connait l’URI du parent de la ressource. La réponse à ce type de POST est généralement 201 (‘Created’). Une fois que cette ressource exist, l’URI est définie et le client peut utiliser les méthodes ‘PUT’, ‘GET’ et ‘DELETE’.

Mais la signification que 99,9% des développeurs connaissent est le ‘POST’ surchargé: c’est la fameuse requête ‘POST’ employée dans les formulaires HTML: l’information sur ce qui doit être fait est contenue dans la requête HTTP (URI, entêtes HTTP, ou le corps de la requête). C’est d’après les auteurs une chose inévitable…!

– GET et HEAD sont des méthodes sûres (safe).

   Implementors should be aware that the software represents the user in
   their interactions over the Internet, and should be careful to allow
   the user to be aware of any actions they might take which may have an
   unexpected significance to themselves or others.

   In particular, the convention has been established that the GET and
   HEAD methods SHOULD NOT have the significance of taking an action
   other than retrieval. These methods ought to be considered "safe".
   This allows user agents to represent other methods, such as POST, PUT
   and DELETE, in a special way, so that the user is made aware of the
   fact that a possibly unsafe action is being requested.

   Naturally, it is not possible to ensure that the server does not
   generate side-effects as a result of performing a GET request; in
   fact, some dynamic resources consider that a feature. The important
   distinction here is that the user did not request the side-effects,
   so therefore cannot be held accountable for them.

– GET, HEAD, PUT et DELETE sont idempotentes.

   Methods can also have the property of "idempotence" in that (aside
   from error or expiration issues) the side-effects of N > 0 identical
   requests is the same as for a single request. The methods GET, HEAD,
   PUT and DELETE share this property. Also, the methods OPTIONS and
   TRACE SHOULD NOT have side effects, and so are inherently idempotent.

Fielding, et al.            Standards Track                    [Page 51]
RFC 2616                        HTTP/1.1                       June 1999

   However, it is possible that a sequence of several requests is non-
   idempotent, even if all of the methods executed in that sequence are
   idempotent. (A sequence is idempotent if a single execution of the
   entire sequence always yields a result that is not changed by a
   reexecution of all, or part, of that sequence.) For example, a
   sequence is non-idempotent if its result depends on a value that is
   later modified in the same sequence.

   A sequence that never has side effects is idempotent, by definition
   (provided that no concurrent operations are being executed on the
   same set of resources).

– la méthode ‘POST’ n’est ni sûre (safe) ni idempotente.

– les auteurs signalent que la méthode ‘GET’ n’a pas été utilisée correctement sur le Web, cette méthode pouvant être unsafe ! Voir Google et son WebAccelerator de 2005.

– les auteurs finissent en constatant que actuellement les formulaires HTML n’autorisent que POST et GET (p.153 les auteurs utilisent ‘PUT’ et ‘DELETE’ qui font partie de la future norme XHTM5, voir http://cafe.elharo.com/web/why-rest-failed/ )

http://www.w3.org/TR/html401/interact/forms.html#adef-method

method = get|post [CI]
This attribute specifies which HTTP method will be used to submit the form data set. Possible (case-insensitive) values are « get » (the default) and « post ». See the section on form submission for usage information.

http://www.whatwg.org/specs/web-forms/current-work/#methodAndEnctypes

« The HTTP specification defines various methods that can be used with HTTP URIs. Four of these may be used as values of the method attribute: get, post, put, and delete. In this specification, these method names are applied to other protocols as well. This section defines how they should be interpreted.

If the specified method is not one of get, post, put, or delete then it is treated as get in the tables below. »

Chapitre 5: « Designing Read_only Resource-Oriented Services

D’abord on définit son ensemble de données (Data Set) et on décide de découper ses données en ressources. Au lieu de penser en termes d’actions, il faut penser en termes de résultats d’une action.

Ensuite, il faut nommer ces ressources (« Name the Resources »). Il faut se rappeler que dans un service orienté ressources, l’URI contient toutes les informations de portée. Quelques conseils:

– utiliser les chemins pour encoder une hiérarchie: /parent/enfant

– utiliser des caractères de ponctuation pour éviter d’employer à nouveau une hiérarchie: /parent/enfant1;enfant2

– utiliser des variables de recherche pour indiquer que l’on attend des entrées: /search?q=cyliste&name=poupou

Maintenant, il faut décider quelles données renvoyées au client et quels formats employer pour ces données (choix de la représentation) lorsqu’un client demande une ressource. Le principal but d’une représentation est de transmettre l’état de la ressource. Une représentation peut être au format XML (avec un vocabulaire spécifique comme XHTML, ATOM, …etc)

En ce qui concerne les réponses HTTP on aura:

– 200 (« OK)

– le Content-Type de l’entête HTTP sera: application/xhtml+xml pour les résultats de recherche et image/png pour les images.

– les auteurs parlent de la méthode ‘GET’ conditionnelle. Il faut utiliser les champs ‘Last-Modified‘, ‘If-Modified-Since‘, la réponse 304 (« Not Modified ») permettant de ne pas recharger une donnée qui n’a pas changée. Voir Chapitre 8 pour plus de détails.



14.25 If-Modified-Since

   The If-Modified-Since request-header field is used with a method to
   make it conditional: if the requested variant has not been modified
   since the time specified in this field, an entity will not be
   returned from the server; instead, a 304 (not modified) response will
   be returned without any message-body.

       If-Modified-Since = "If-Modified-Since" ":" HTTP-date

Fielding, et al.            Standards Track                   [Page 130]
 
RFC 2616                        HTTP/1.1                       June 1999

   An example of the field is:

       If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT

   A GET method with an If-Modified-Since header and no Range header
   requests that the identified entity be transferred only if it has
   been modified since the date given by the If-Modified-Since header.
   The algorithm for determining this includes the following cases:

      a) If the request would normally result in anything other than a
         200 (OK) status, or if the passed If-Modified-Since date is
         invalid, the response is exactly the same as for a normal GET.
         A date which is later than the server's current time is
         invalid.

      b) If the variant has been modified since the If-Modified-Since
         date, the response is exactly the same as for a normal GET.

      c) If the variant has not been modified since a valid If-
         Modified-Since date, the server SHOULD return a 304 (Not
         Modified) response.

   The purpose of this feature is to allow efficient updates of cached
   information with a minimum amount of transaction overhead.

      Note: The Range request-header field modifies the meaning of If-
      Modified-Since; see section 14.35 for full details.

      Note: If-Modified-Since times are interpreted by the server, whose
      clock might not be synchronized with the client.

      Note: When handling an If-Modified-Since header field, some
      servers will use an exact date comparison function, rather than a
      less-than function, for deciding whether to send a 304 (Not
      Modified) response. To get best results when sending an If-
      Modified-Since header field for cache validation, clients are
      advised to use the exact date string received in a previous Last-
      Modified header field whenever possible.

      Note: If a client uses an arbitrary date in the If-Modified-Since
      header instead of a date taken from the Last-Modified header for
      the same request, the client should be aware of the fact that this
      date is interpreted in the server's understanding of time. The
      client should consider unsynchronized clocks and rounding problems
      due to the different encodings of time between the client and
      server. This includes the possibility of race conditions if the
      document has changed between the time it was first requested and
      the If-Modified-Since date of a subsequent request, and the

Fielding, et al.            Standards Track                   [Page 131]
 
RFC 2616                        HTTP/1.1                       June 1999

      possibility of clock-skew-related problems if the If-Modified-
      Since date is derived from the client's clock without correction
      to the server's clock. Corrections for different time bases
      between client and server are at best approximate due to network
      latency.

   The result of a request having both an If-Modified-Since header field
   and either an If-Match or an If-Unmodified-Since header fielfields is
   undefined by this specification

10.3.5 304 Not Modified

If the client has performed a conditional GET request and access is
allowed, but the document has not been modified, the server SHOULD
respond with this status code. The 304 response MUST NOT contain a
message-body, and thus is always terminated by the first empty line
after the header fields.

The response MUST include the following header fields:

- Date, unless its omission is required by section 14.18.1

Fielding, et al. Standards Track [Page 63]

RFC 2616 HTTP/1.1 June 1999

If a clockless origin server obeys these rules, and proxies and
clients add their own Date to any response received without one (as
already specified by [RFC 2068], section 14.19), caches will operate
correctly.

- ETag and/or Content-Location, if the header would have been sent
in a 200 response to the same request

- Expires, Cache-Control, and/or Vary, if the field-value might
differ from that sent in any previous response for the same
variant

If the conditional GET used a strong cache validator (see section
13.3.3), the response SHOULD NOT include other entity-headers.
Otherwise (i.e., the conditional GET used a weak validator), the
response MUST NOT include other entity-headers; this prevents
inconsistencies between cached entity-bodies and updated headers.

If a 304 response indicates an entity not currently cached, then the
cache MUST disregard the response and repeat the request without the
conditional.

If a cache uses a received 304 response to update a cache entry, the
cache MUST update the entry to reflect any new field values given in
the response.

Chapitre 6: « Designing Read/Write Resource-Oriented Services »

Qui dit écriture dit ouverture d’un compte utilisateur qui devient une ressource avec les problèmes d’authentification et d’autorisation associés. Il faut utiliser le champ entête ‘Authorization


14.8 Authorization

A user agent that wishes to authenticate itself with a server-- usually, but not necessarily, after receiving a 401 response--does so by including an Authorization request-header field with the request. The Authorization field value consists of credentials containing the authentication information of the user agent for the realm of the resource being requested. Authorization = "Authorization" ":" credentials HTTP access authentication is described in "HTTP Authentication: Basic and Digest Access Authentication" [43]. If a request is authenticated and a realm specified, the same credentials SHOULD be valid for all other requests within this realm (assuming that the authentication scheme itself does not require otherwise, such as credentials that vary according to a challenge value or using synchronized clocks). When a shared cache (see section 13.7) receives a request containing an Authorization field, it MUST NOT return the corresponding response as a reply to any other request, unless one of the following specific exceptions holds: 1. If the response includes the "s-maxage" cache-control directive, the cache MAY use that response in replying to a subsequent request. But (if the specified maximum age has passed) a proxy cache MUST first revalidate it with the origin server, using the request-headers from the new request to allow the origin server to authenticate the new request. (This is the defined behavior for s-maxage.) If the response includes "s- maxage=0", the proxy MUST always revalidate it before re-using it. 2. If the response includes the "must-revalidate" cache-control directive, the cache MAY use that response in replying to a subsequent request. But if the response is stale, all caches MUST first revalidate it with the origin server, using the request-headers from the new request to allow the origin server to authenticate the new request. 3. If the response includes the "public" cache-control directive, it MAY be returned in reply to any subsequent request.

Si la réponse est 401 (« Unauthorized ») la réponse doit inclure champ entête ‘WWW-Authenticate‘.


10.4.2 401 Unauthorized

The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication" [43].

Les principaux mécanismes d’authentification sont ‘HTTP basic, ‘HTTP Digest’ (http://tools.ietf.org/html/rfc2617, HTTP Authentication: Basic and Digest Access Authentication) et ‘WSSE’ qui sont très peu sécurisés. Voir chapitre 8 pour plus de détails.

Les auteurs parlent à nouveau de XHTML5 (http://www.whatwg.org/specs/web-apps/current-work/, HTML 5 Working Draft — 28 June 2007) qui permettra (quand ?) d’utiliser ‘PUT’ et ‘DELETE’ dans les formulaires. Ils parlent du nouvel attribut ‘template’ (pas encore approuvé , voir http://tools.ietf.org/id/draft-gregorio-uritemplate-00.txt )

   A URI Template is a sequence of characters that contains one or more
   embedded template variables Section 4.1.  A URI Template becomes a
   URI when the template variables are substituted with the template
   variables string values, see Section 4.2.  The following shows an
   example URI Template:

   http://example.com/widgets/widget_id

   If the value of the widget_id variable is "xyzzy", the resulting URI
   after substitution is:

   http://example.com/widgets/xyzzy

Chapitre 7: « A service implementation »

Les auteurs rappellent que jusqu’à présent les frameworks Web se sont focalisés sur les applications web pour les butineurs Web (web browser) et qu’ils n’utilisaient donc que les 2 seuls méthodes possibles GET et ‘POST’ (voir http://cafe.elharo.com/web/why-rest-failed/ et http://www.w3.org/TR/html401/interact/forms.html#adef-method).

De nouveaux frameworks pour développer des services RESTful sont apparus: Django (Python), Restlet (Java) et Ruby On Rails. (ces frameworks seront détaillés au chapitre 12)

Le but de ce chapitre est d’écrire une application de type ‘social bookmarking’ RESTful avec RubyOnRails. Alors allons-y !

pve@pc72 /cygdrive/e/projets
$ rails bookmarks
create
create app/controllers
create app/helpers
create app/models
create app/views/layouts
create config/environments
create components
create db
create doc
create lib
create lib/tasks
create log
create public/images
create public/javascripts
create public/stylesheets
create script/performance
create script/process
create test/fixtures
create test/functional
create test/integration
create test/mocks/developmen
create test/mocks/test
create test/unit
create vendor
create vendor/plugins
create tmp/sessions
create tmp/sockets
create tmp/cache
create tmp/pids
create Rakefile
create README
create app/controllers/appli
create app/helpers/applicati
create test/test_helper.rb
create config/database.yml
create config/routes.rb
create public/.htaccess
create config/boot.rb
create config/environment.rb
create config/environments/p
create config/environments/d
create config/environments/t
create script/about
create script/breakpointer
create script/console
create script/destroy
create script/generate
create script/performance/be
create script/performance/pr
create script/process/reaper
create script/process/spawne
create script/process/inspec
create script/runner
create script/server
create script/plugin
create public/dispatch.rb
create public/dispatch.cgi
create public/dispatch.fcgi
create public/404.html
create public/500.html
create public/index.html
create public/favicon.ico
create public/robots.txt
create public/images/rails.p
create public/javascripts/pr
create public/javascripts/ef
create public/javascripts/dr
create public/javascripts/co
create public/javascripts/ap
create doc/README_FOR_APP
create log/server.log
create log/production.log
create log/development.log
create log/test.log

pve@pc72 /cygdrive/e/projets

$ script/plugin discover
Add http://www.agilewebdevelopment.com/plugins/? [Y/n] Y
Add svn://rubyforge.org/var/svn/expressica/plugins/? [Y/n] Y
Add http://soen.ca/svn/projects/rails/plugins/? [Y/n] Y
Add http://technoweenie.stikipad.com/plugins/? [Y/n] Y
Add http://svn.techno-weenie.net/projects/plugins/? [Y/n] Y
Add http://svn.recentrambles.com/plugins/? [Y/n] Y
Add http://opensvn.csie.org/rails_file_column/plugins/? [Y/n] Y
Add http://svn.protocool.com/rails/plugins/? [Y/n] Y
Add http://tools.assembla.com/svn/breakout/breakout/vendor/plugins/? [Y/
Add http://svn.pragprog.com/Public/plugins/? [Y/n] Y
Add http://source.collectiveidea.com/public/rails/plugins/? [Y/n] Y
Add https://secure.near-time.com/svn/plugins/? [Y/n] Y
Add http://svn.inlet-media.de/svn/rails_extensions/plugins/? [Y/n] Y
Add http://svn.viney.net.nz/things/rails/plugins/? [Y/n] Y
Add http://svn.hasmanythrough.com/public/plugins/? [Y/n] Y
Add http://svn.shiftnetwork.com/plugins/? [Y/n] Y
Add svn://caboo.se/plugins/? [Y/n] Y
Add http://svn.6brand.com/projects/plugins/? [Y/n] Y
Add http://shanesbrain.net/svn/rails/plugins/? [Y/n] Y
Add svn://errtheblog.com/svn/plugins/? [Y/n] Y
Add http://svn.nkryptic.com/plugins/? [Y/n] Y
Add http://svn.thoughtbot.com/plugins/? [Y/n] Y
Add http://svn.webwideconsulting.com/plugins/? [Y/n] Y
Add http://invisible.ch/svn/projects/plugins/? [Y/n] Y
Add svn://rubyforge.org/var/svn/enum-column/plugins/? [Y/n] Y
Add http://streamlinedframework.org:8079/streamlined/plugins/? [Y/n] Y
Add svn://dvisionfactory.com/rails/plugins/? [Y/n] Y
Add http://hivelogic.com/plugins/? [Y/n] Y
Add http://mattmccray.com/svn/rails/plugins/? [Y/n] Y
Add svn://rubyforge.org/var/svn/cartographer/plugins/? [Y/n] Y
Add http://www.svn.recentrambles.com/plugins/? [Y/n] Y
Add http://tanjero.com/svn/plugins/? [Y/n] Y
Add http://filetofsole.org/svn/public/projects/rails/plugins/? [Y/n] Y
Add http://topfunky.net/svn/plugins/? [Y/n] Y
Add http://svn.joshpeek.com/projects/plugins/? [Y/n] Y
Add svn://rubyforge.org/var/svn/agtools/plugins/? [Y/n] Y
Add http://svn.aviditybytes.com/rails/plugins/? [Y/n] Y
Add http://beautifulpixel.textdriven.com/svn/plugins/? [Y/n] Y
Add http://mabs29.googlecode.com/svn/trunk/plugins/? [Y/n] Y
Add http://www.codyfauser.com/svn/projects/plugins/? [Y/n] Y
Add http://craz8.com/svn/trunk/plugins/? [Y/n] Y
Add http://sean.treadway.info/svn/plugins/? [Y/n] Y
Add http://svn.thebootstrapnation.com/public/plugins/? [Y/n] Y
Add http://www.mattmccray.com/svn/rails/plugins/? [Y/n] Y
Add svn://rubyforge.org//var/svn/validaterequest/plugins/? [Y/n] Y
Add http://sprocket.slackworks.com/svn/rails/plugins/? [Y/n] Y
Add http://svn.simpltry.com/plugins/? [Y/n] Y
Add http://svn.elctech.com/svn/public/plugins/? [Y/n] Y
Add http://xmlblog.stikipad.com/plugins/? [Y/n] Y
Add http://www.xml-blog.com/svn/plugins/? [Y/n] Y
Add http://svn.toolbocks.com/plugins/? [Y/n] Y
Add http://thar.be/svn/projects/plugins/? [Y/n] Y
Add http://code.teytek.com/rails/plugins/? [Y/n] Y
Add http://www.infused.org/svn/plugins/? [Y/n] Y
Add svn://rubyforge.org/var/svn/apptrain/trunk/vendor/plugins/? [Y/n] Y
Add http://s3cachestore.googlecode.com/svn/trunk/plugins/? [Y/n] Y
Add http://sbecker.net/shared/plugins/? [Y/n] Y
Add http://opensvn.csie.org/macaque/plugins/? [Y/n] Y
Add http://svn.designbyfront.com/rails/plugins/? [Y/n] Y
Add http://svn.rails-engines.org/plugins/? [Y/n] Y
Add http://dev.fiatdev.com/svn/plugins/? [Y/n] Y
Add http://john.guen.in/svn/plugins/? [Y/n] Y
Add http://www.redhillonrails.org/svn/trunk/vendor/plugins/? [Y/n] Y
Add svn://rubyforge.org/var/svn/actsdisjoint/plugins/? [Y/n] Y
Add http://ajaxmessaging.googlecode.com/svn/trunk/plugins/? [Y/n] Y
Add http://mod-i18n.googlecode.com/svn/trunk/plugins/? [Y/n] Y

$ script/plugin install acts_as_taggable
svn: Can’t connect to host ‘rubyforge.org’: Connect
svn: Can’t connect to host ‘caboo.se’: Connection t
svn: Can’t connect to host ‘errtheblog.com’: Connec
svn: Can’t connect to host ‘rubyforge.org’: Connect
svn: Can’t connect to host ‘dvisionfactory.com’: Co
svn: Can’t connect to host ‘rubyforge.org’: Connect
+ ./acts_as_taggable/MIT-LICENSE
+ ./acts_as_taggable/README
+ ./acts_as_taggable/generators/acts_as_taggable_ta
generator.rb
+ ./acts_as_taggable/generators/acts_as_taggable_ta
+ ./acts_as_taggable/init.rb
+ ./acts_as_taggable/lib/acts_as_taggable.rb
+ ./acts_as_taggable/lib/tag.rb
+ ./acts_as_taggable/lib/tagging.rb
+ ./acts_as_taggable/tasks/acts_as_taggable_tasks.r
+ ./acts_as_taggable/test/acts_as_taggable_test.rb

$ script/plugin install http_authentication
svn: Can’t connect to host ‘rubyforge.org’:
svn: Can’t connect to host ‘caboo.se’: Conn
svn: Can’t connect to host ‘errtheblog.com’
svn: Can’t connect to host ‘rubyforge.org’:
svn: Can’t connect to host ‘dvisionfactory.
svn: Can’t connect to host ‘rubyforge.org’:
svn: Can’t connect to host ‘rubyforge.org’:
svn: Can’t connect to host ‘rubyforge.org’:
svn: Can’t connect to host ‘rubyforge.org’:
svn: Can’t connect to host ‘rubyforge.org’:
Plugin not found: [« http_authentication »]

Chapitre 8: « REST and ROA Best Practices »

Une récapitulation des bonnes pratiques.

Chapitre 9: « The building Blocks of Services »

Pour rappeler que les services Web sont basés sur 3 technologies fondamentales: HTTP, URIs et XML.

Les auteurs nous parlent des formats de représentation tels que XHTML (mime-type: application/xhtml+xml), les microformats, Atom, OpenSearch, SVG, form-encode Key-Value Pairs (application/x-www-form-urlencode), JSON, RDF, RDFa.

On nous parle de l’encodage de caractères . Aux Etats Unis, on utilise UTF-8, US-ASCII ou Windows 1252. En Europe on utilise l’ISO-8859-1. Au Japon on utilise EUC-JP, Shift-JS ou UTF-8.

L’utilisation de la norme Unicode permet de mettre de l’ordre dans l’utilisation de tous ces différents codages en utilisant 2 formes de transformation universelle que sont UTF-8 et UTF-16 (pour les langues asiatiques).

Il existe un excellent détecteur d’encode universal écrit en python (http://chardet.feedparser.org)

 

>>> import urllib
>>> urlread = lambda url: urllib.urlopen(url).read()
>>> import chardet
>>> chardet.detect(urlread("http://google.cn/"))
{'encoding': 'GB2312', 'confidence': 0.99}

>>> chardet.detect(urlread("http://yahoo.co.jp/"))
{'encoding': 'EUC-JP', 'confidence': 0.99}

>>> chardet.detect(urlread("http://amazon.co.jp/"))
{'encoding': 'SHIFT_JIS', 'confidence': 1}

>>> chardet.detect(urlread("http://pravda.ru/"))
{'encoding': 'windows-1251', 'confidence': 0.9355}

>>> chardet.detect(urlread("http://auction.co.kr/"))
{'encoding': 'EUC-KR', 'confidence': 0.99}

>>> chardet.detect(urlread("http://haaretz.co.il/"))
{'encoding': 'windows-1255', 'confidence': 0.99}

>>> chardet.detect(urlread("http://www.nectec.or.th/tindex.html"))
{'encoding': 'TIS-620', 'confidence': 0.7675}

>>> chardet.detect(urlread("http://feedparser.org/docs/"))
{'encoding': 'utf-8', 'confidence': 0.99}


Copyright © 2006 Mark Pilgrim · mark@diveintomark.org · Terms of use

XML permet de dire au client quel encodage on a utilisé en le spécifiant sur la première ligne du fichier XML:

<?xml version= »1.0″ encoding= »UTF-8″?>

HTTP avec son attribut d’entête Content-Type peut indiquer également l’encodage utilisé et il est préférable que cela soit le même que le document XML transmis. Si il est différent c’est le codage défini pat Content-Type qui prime. Ceci est un piège !


14.17 Content-Type

The Content-Type entity-header field indicates the media type of the entity-body sent to the recipient or, in the case of the HEAD method, the media type that would have been sent had the request been a GET. Content-Type = "Content-Type" ":" media-type Media types are defined in section 3.7. An example of the field is Content-Type: text/html; charset=ISO-8859-4 Further discussion of methods for identifying the media type of an entity is provided in section 7.2.1.

Pour ces problèmes voir http://tools.ietf.org/html/rfc3023 (XML Media Types) et l’article de Mark Pilgrim « XML on the Web Has Failed » http://www.xml.com/pub/a/2004/07/21/dive.html

Description des protocoles:

APP , http://tools.ietf.org/wg/atompub/ .

– GData qui est une extension de APP (http://code.google.com/apis/gdata/clientlibs.html). Les applications Blogger, Google Calendar, Google code search et Google spreadsheet exposent toutes des services web RESTful avec la même interface : le Protocole de Publication Atom (APP) avec les extensions GData.

Les auteurs parlent ensuite de ‘POE’ (Post Once Exactly, http://www.mnot.net/drafts/draft-nottingham-http-poe-00.txt ), des URI templates, de XHTML4 et de ses nombreuses limitations.

Pour XHTML5 le problème est sa date d’adoption: de fin 2008 à 2022 pour les plus réalistes :(. Voir http://blog.welldesignedurls.org)

Je passe sur WADL.

Chapitre 10 : The Resource-Oriented Architecture Versus Big Web Services

Bon ce sont toutes les technologies SOAP, WSDL WS-: je passe.

Chapitre 11: Ajax applications as REST clients

Pour les auteurs une application AJAX est un service web client qui tourne à l’intérieur d’un butineur (web browser)

Gmail est un service web et il existe une bibliothèque d’accès à ce service: http://libgmail.sourceforge.net (http://libgmail.sourceforge.net/, « Python binding for Google’s Gmail service »).

AJAX est devenu Ajax car pour les auteurs Ajax est un style d’architecture qui n’a pas nécessairement besoin ni de Javascript(on peut utiliserActionScript, Java, VBScript, python) ni de XML (on peut utiliser JSON, du HTML, du texte).

Presque tous les butineurs fournissent un objet javascript XMLHttpRequest avec les 5 méthodes HTTP de base: GET, HEAD, POST, PUT et DELETE avec la possibilité de modifier l’entête et le corps d’une requête HTTP. Un site pour tester son navigateur: http://mnot.net/javascript/xmlhttprequest/

Etant donné les différences d’implémentation de Javascript il est fortement conseillé d’employer des bibliothèques.

Bibliothèques utilisées pour Javascript:

Prototype : Attention: on ne peut pas modifier les champs d’entête !

Dojo

Pour plus d’informations sur les biblothèques Javascript voir http://en.wikipedia.org/wiki/Category:JavaScript_libraries . La bibliothèque Javascript qui monte est la bibliothèque jQuery voir http://docs.jquery.com/Sites_Using_jQuery

Je passe sur JoD (Javascript on Demand)

Chapitre 12 : Frameworks for RESTful Services

Dans ce dernier chapitre, les auteurs passent en revue 3 frameworks REStful: Ruby On rails, Restlet (Java) et Django (Python).

Ruby On Rails:

doit son succès au fait de respecter des conventions. La version 1.2 a une conception RESTful

Restlet

Restlet a été influencé par les technologies majeures de Java: l’API Servlet, les Java Server Pages , HTTPUrlConnection et Struts .

Voir Retrotranslator (http://retrotranslator.sourceforge.net/#what)

Django

La conception de Django est similaire à celle de Rails bien qu’ils fassent moins de simplifications.

Installation:

# extraction des sources django
$ svn co http://code.djangoproject.com/svn/django/trunk/ ~/django_src

$ python -c « from distutils.sysconfig import get_python_lib; print get_python_lib() »
/usr/lib/python2.5/site-packages

$ ln -s /cygdrive/h/django_src/django /usr/lib/python2.5/site-packages/django

# on met django-admin.py dans le chemin PATH

$ ln -s ~/django_src/django/bin/django-admin.py /usr/local/bin

pve@pc72 ~/django_src
$ which django-admin.py
/usr/local/bin/django-admin.py

// Le lendemain ==> mise à jour de django

$ cd ~/django_src; svn update
U django/test/client.py
U django/contrib/auth/__init__.py
U tests/modeltests/test_client/fixtures/testdata.json
U tests/modeltests/test_client/models.py
Updated to revision 5678.

# installation du projet django: voir http://www.djangoproject.com/documentation/tutorial01/

cd /cygdrive/e/projets/

Writing your first Django app, part 1 (http://www.djangoproject.com/documentation/tutorial01/)

Création du projet pybookmarks

$ date; django-admin.py startproject pybookmarks; date
Fri Jul 13 09:03:02 2007
Fri Jul 13 09:03:04 2007

pve@pc72 /cygdrive/e/projets
$ ls -als pybookmarks/
total 48
0 drwxr-xr-x 2 pve mkgroup-l-d 0 Jul 13 09:03 .
0 drwxr-xr-x 6 pve mkgroup-l-d 0 May 10 11:19 ..
0 -rw-r–r– 1 pve mkgroup-l-d 0 Jul 13 09:03 __init__.py
16 -rwxr-xr-x 1 pve mkgroup-l-d 546 Jul 13 09:03 manage.py
16 -rw-r–r– 1 pve mkgroup-l-d 2933 Jul 13 09:03 settings.py
16 -rw-r–r– 1 pve mkgroup-l-d 235 Jul 13 09:03 urls.py

pve@pc72 /cygdrive/e/projets/pybookmarks
$ python manage.py runserver
Validating models…
0 errors found.

Django version 0.97-pre, using settings ‘pybookmarks.settings’
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Projet django initial

voir:Pour la base de données j’ai dû choisir le site “ftp://sunsite.dk/projects/cygwinports” pour pouvoir installer la base de données sqlite3. Pour vérifier que la base sqlite3 est opérationnelle je fais:

$ python
Python 2.5.1 (r251:54863, Jun 19 2007, 22:55:07)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type « help », « copyright », « credits » or « license » for more information.
>>> import sqlite3
>>>

Modication du fichier /cygdrive/e/projets/pybookmarks/settings.py

modification du fichier applicatif setting.py

 pve@pc72 /cygdrive/e/projets/pybookmarks
$ python manage.py syncdb
Creating table auth_message
Creating table auth_group
Creating table auth_user
Creating table auth_permission
Creating table django_content_type
Creating table django_session
Creating table django_site

You just installed Django’s auth system, which means you don’t have any superuse
rs defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use ‘pve’):
E-mail address: pvergain@gmail.com
Password:
Password (again):
Superuser created successfully.
Installing index for auth.Message model
Installing index for auth.Permission model
Loading ‘initial_data’ fixtures…
No fixtures found.

# Création de notre application
$ date; python manage.py startapp bookmarks; date
Fri Jul 13 13:03:58     2007
Fri Jul 13 13:04:00     2007

pve@pc72 /cygdrive/e/projets/pybookmarks
$ ls -als bookmarks/
total 32
0 drwxr-xr-x 2 pve mkgroup-l-d  0 Jul 13 13:04 .
0 drwxr-xr-x 3 pve mkgroup-l-d  0 Jul 13 09:03 ..
0 -rw-r–r– 1 pve mkgroup-l-d  0 Jul 13 13:04 __init__.py
16 -rw-r–r– 1 pve mkgroup-l-d 57 Jul 13 13:04 models.py
16 -rw-r–r– 1 pve mkgroup-l-d 26 Jul 13 13:04 views.py

Modification du modèle de données (models.py)


     Le modèle de données

ATTENTION: ne pas oublier le codage dans l’entête du fichier + la méthode __unicode__ non décrite dans le bouquin !

#!/usr/bin/python
# -*- coding: UTF-8 -*-

pve@pc72 /cygdrive/e/projets/pybookmarks
$ python manage.py sql bookmarks
BEGIN;
CREATE TABLE « bookmarks_bookmark » (
« id » integer NOT NULL PRIMARY KEY,
« user_id » integer NOT NULL,
« url » varchar(200) NOT NULL,
« short_description » varchar(255) NOT NULL,
« long_description » text NOT NULL,
« timestamp » datetime NOT NULL,
« public » bool NOT NULL
)
;
CREATE TABLE « bookmarks_tag » (
« id » integer NOT NULL PRIMARY KEY,
« name » varchar(100) NOT NULL
)
;
CREATE TABLE « bookmarks_bookmark_tags » (
« id » integer NOT NULL PRIMARY KEY,
« bookmark_id » integer NOT NULL REFERENCES « bookmarks_bookmark » (« id »),
« tag_id » integer NOT NULL REFERENCES « bookmarks_tag » (« id »),
UNIQUE (« bookmark_id », « tag_id »)
)
;
COMMIT;

If you’re interested, also run the following commands:
  • python manage.py validate pybookmarks — Checks for any errors in the construction of your models.
  • python manage.py sqlcustom pybookmarks — Outputs any custom SQL statements (such as table modifications or constraints) that are defined for the application.
  • python manage.py sqlclear pybookmarks — Outputs the necessary DROP TABLE statements for this app, according to which tables already exist in your database (if any).
  • python manage.py sqlindexes pybookmarks — Outputs the CREATE INDEX statements for this app.
  • python manage.py sqlall pybookmarks — A combination of all the SQL from the ‘sql’, ‘sqlcustom’, and ‘sqlindexes’ commands.

Looking at the output of those commands can help you understand what’s actually happening under the hood.

Looking at the output of those commands can help you understand what’s actually happening under the hood.

$ python manage.py syncdb
Creating table auth_message
Creating table auth_group
Creating table auth_user
Creating table auth_permission
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table bookmarks_bookmark
Creating table bookmarks_tag

You just installed Django’s auth system, which mean
rs defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use ‘pve’):
E-mail address: pvergain@gmail.com
Password:
Password (again):
Superuser created successfully.
Installing index for auth.Message model
Installing index for auth.Permission model
Installing index for bookmarks.Bookmark model
Installing index for bookmarks.Tag model
Loading ‘initial_data’ fixtures…
No fixtures found.

Writing your first Django app, part 2 (http://www.djangoproject.com/documentation/tutorial02/)

Generating admin sites for your staff or clients to add, change and delete content is tedious work that doesn’t require much creativity. For that reason, Django entirely automates creation of admin interfaces for models.

Django was written in a newsroom environment, with a very clear separation between “content publishers” and the “public” site. Site managers use the system to add news stories, events, sports scores, etc., and that content is displayed on the public site. Django solves the problem of creating a unified interface for site administrators to edit content.

The admin isn’t necessarily intended to be used by site visitors; it’s for site managers.

Add "django.contrib.admin" to your INSTALLED_APPS setting.

INSTALLED_APPS = (
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.sites’,
‘pybookmarks.bookmarks’,
‘django.contrib.admin’,
)

Run python manage.py syncdb. Since you have added a new application to INSTALLED_APPS, the database tables need to be updated.

$ python manage.py syncdb
Creating table django_admin_log
Installing index for admin.LogEntry model
Loading ‘initial_data’ fixtures…
No fixtures found.

Edit your mysite/urls.py file and uncomment the line below “Uncomment this for admin:”. This file is a URLconf; we’ll dig into URLconfs in the next tutorial. For now, all you need to know is that it maps URL roots to applications.

Recall from Tutorial 1 that you start the development server like so:

python manage.py runserver

Now, open a Web browser and go to “/admin/” on your local domain — e.g., http://127.0.0.1:8000/admin/. You should see the admin’s login screen:

Administration django

 

Just one thing to do: We need to specify in the bookmarks model that Bookmark objects have an admin interface. Edit the pybookmarks/bookmarks/models.py file and make the following change to add an inner Admin class:

The class Admin will contain all the settings that control how this model appears in the Django admin. All the settings are optional, however, so creating an empty class means “give this object an admin interface using all the default options.

Now reload the Django admin page to see your changes. Note that you don’t have to restart the development server — the server will auto-reload your project, so any modifications code will be seen immediately in your browser.

 Et ça marche !

 Admin bookmarks

Saisie d’un bookmark

Things to note here:

  • The form is automatically generated from the Poll model.
  • The different model field types (models.DateTimeField, models.CharField) correspond to the appropriate HTML input widget. Each type of field knows how to display itself in the Django admin.
  • Each DateTimeField gets free JavaScript shortcuts. Dates get a “Today” shortcut and calendar popup, and times get a “Now” shortcut and a convenient popup that lists commonly entered times.

Writing your first Django app, part 3 (http://www.djangoproject.com/documentation/tutorial03/)

Installation de dateutil: d’abord le télécharger, le décompresser, aller sous le répertoire python-dateutil et faire ‘python setup.py install’

$ python setup.py install
running install
running build
running build_py
creating build
creating build/lib
creating build/lib/dateutil
copying dateutil/__init__.py -> build/lib/dateutil
copying dateutil/easter.py -> build/lib/dateutil
copying dateutil/parser.py -> build/lib/dateutil
copying dateutil/relativedelta.py -> build/lib/dateutil
copying dateutil/rrule.py -> build/lib/dateutil
copying dateutil/tz.py -> build/lib/dateutil
copying dateutil/tzwin.py -> build/lib/dateutil
creating build/lib/dateutil/zoneinfo
copying dateutil/zoneinfo/__init__.py -> build/lib/dateutil/zoneinfo
running install_lib
creating /usr/lib/python2.5/site-packages/dateutil
copying build/lib/dateutil/__init__.py -> /usr/lib/python2.5/site-packages/dateutil
copying build/lib/dateutil/easter.py ->/usr/lib/python2.5/site-packages/dateutil
copying build/lib/dateutil/parser.py -> /usr/lib/python2.5/site-packages/dateutil
copying build/lib/dateutil/relativedelta.py -> /usr/lib/python2.5/site-packages/dateutil
copying build/lib/dateutil/rrule.py -> /usr/lib/python2.5/site-packages/dateutil

copying build/lib/dateutil/tz.py -> /usr/lib/python2.5/site-packages/dateutil
copying build/lib/dateutil/tzwin.py -> /usr/lib/python2.5/site-packages/dateutil

creating /usr/lib/python2.5/site-packages/dateutil/zoneinfo
copying build/lib/dateutil/zoneinfo/__init__.py -> /usr/lib/python2.5/site-packages/dateutil/zoneinfo
byte-compiling /usr/lib/python2.5/site-packages/dateutil/__init__.py to __init__
.pyc
byte-compiling /usr/lib/python2.5/site-packages/dateutil/easter.py to easter.pyc
byte-compiling /usr/lib/python2.5/site-packages/dateutil/parser.py to parser.pyc
byte-compiling /usr/lib/python2.5/site-packages/dateutil/relativedelta.py to relativedelta.pyc
byte-compiling /usr/lib/python2.5/site-packages/dateutil/rrule.py to rrule.pyc
byte-compiling /usr/lib/python2.5/site-packages/dateutil/tz.py to tz.pyc
byte-compiling /usr/lib/python2.5/site-packages/dateutil/tzwin.py to tzwin.pyc
byte-compiling /usr/lib/python2.5/site-packages/dateutil/zoneinfo/__init__.py to
__init__.pyc
running install_data
copying dateutil/zoneinfo/zoneinfo-2007f.tar.gz -> /usr/lib/python2.5/site-packages/dateutil/zoneinfo
running install_egg_info
Writing /usr/lib/python2.5/site-packages/python_dateutil-1.2-py2.5.egg-info

# On vérifie que ça marche
$ python
Python 2.5.1 (r251:54863, Jun 19 2007, 22:55:07)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type « help », « copyright », « credits » or « license » for more information.

>>> import dateutil.parser
>>>
La suite la semaine prochaine.

http://www.djangosites.org/latest/

http://www.djangobook.com/

http://www.djangoproject.com/

Posted in Architecture logicielle, http, python, REST, ruby, URI, Web applications, XHTML5, XML | Leave a Comment »

Outils de gestion de version (subversion,mercurial), gestion de projet (trac), intégration continue (buildbot)

Posted by patrick sur juillet 9, 2007

En lisant l’excellent blog de Tarek ziade (http://programmation-python.org/sections/blog) je tombe sur les sujets qui m’intéressent aujourd’hui:

1) la gestion de version aussi bien centralisée (avec subversion de préférence à cvs) que décentralisée (mercurial ou bazaar-ng).

2) la gestion de projet avec un outil comme trac

3) l’intégration continue(« L’intégration continue est une technique utilisée en génie logiciel. Elle consiste à vérifier à chaque modification de code source que le résultat des modifications ne produit pas de régression de l’application en cours de développement. Bien que le concept existait auparavant, l »intégration continue » se réfère généralement a la pratique de l’extreme programming« ) avec buildbot (« BuildBot is a software development continuous integration tool which automates the compile/test cycle required to validate changes to the project code base. It began as an light-weight alternative to the Mozilla project’s Tinderbox« )

En ce qui concerne subversion, trac et builbot, un excellent document d’Olivier Ramonat et Pascal Obry cité par Tarek: http://olivier.ramonat.free.fr/svn_trac_buildbot/svn_trac_buildbot_fr.html (« Ce document porte sur l’installation sur un serveur d’une suite d’outils de gestion informatique:

  • Subversion (gestion de version) pour le contrôle de version;
  • Trac (gestion de projet) pour la gestion de projet : Wiki, système de gestion de tickets et suivi de l’évolution des sources (quand il est couplé à Subversion);
  • et Buildbot (intégration continue) pour l’automatisation du packaging, des compilations et des tests.

Ces trois outils peuvent interagir et permettent ensemble d’améliorer la qualité et la rapidité d’un développement logiciel. Installés sur un serveur, ils peuvent être partagés par différents projets très facilement. Il est possible de réaliser l’installation de plusieurs manières. Ce document propose un modèle d’installation et d’administration qui se veut cohérent, simple et sécurisé. »)

Webographie:

http://en.wikipedia.org/wiki/List_of_revision_control_software

http://trac.edgewall.org/wiki/TracMercurial (« There is an experimental plugin for Trac 0.10 and Trac 0.11 which enables Mercurial to be used instead of Subversion as the VersioningSystemBackend for Trac. The plugin being experimental, expect some rough edges and a somewhat unstable set of features/documentation… »)

http://hgbook.red-bean.com/hgbook.pdf (« Distributed revision control with Mercurial…If the core functionality of Mercurial is not enough for you, it’s easy to build on. Mercurial is well suited to scripting tasks, and its clean internals and implementation in Python make it easy to add features in the form of extensions. There are a number of popular and useful extensions already available, ranging from helping to identify bugs to improving performance…Subversion is a popular revision control tool, developed to replace CVS. It has a centralised client/server architecture. Subversion and Mercurial have similarly named commands for performing the same operations, so it is easy for a
person who is familiar with one to learn to use the other. Both tools are portable to all popular operating systems
« )

http://fr.wikipedia.org/wiki/Subversion_logiciel (« Subversion a été écrit afin de combler certains manques de CVS. Voici les principaux apports :

  • Les commits, ou publications des modifications sont atomiques. Un serveur Subversion utilise de façon sous-jacente une base de données capable de gérer les transactions atomiques (le plus souvent Berkeley DB) ;
  • Subversion permet le renommage et déplacement de fichiers ou de répertoires sans en perdre l’historique. ;
  • les méta-données sont versionnées : on peut attacher des propriétés, comme les permissions, à un fichier, par exemple)

http://fr.wikipedia.org/wiki/Mercurial (« Mercurial est un logiciel de gestion de version distribué. Il est disponible sur plusieurs plate-formes : Unix-like, Windows, Mac OS X. Il est écrit principalement en Python. Mercurial a été créé pour s’utiliser via des lignes de commande. Toutes les commandes commencent par hg, en référence au symbole chimique du mercure. Ses principales caractéristiques sont entre autres :

  • sa rapidité et sa capacité à gérer les gros projets
  • son utilisation sans nécessiter un serveur
  • son fonctionnement complètement distribué
  • sa robustesse dans la gestion des fichiers ASCII et binaires
  • sa gestion avancée des branches et des fusions
  • son interface web intégrée »)
  • Logo mercurial

http://fr.wikipedia.org/wiki/Gestion_de_version_d%C3%A9centralis%C3%A9e (« Quand on pense à la gestion de version, on a, en général, une vision centralisée des choses. En gros, on s’imagine un mécanisme qui va permettre à plusieurs intervenants de collecter leurs interventions. Or, en particulier avec l’arrivée des logiciels libres et leur développement communautaire, une autre façon de voir la gestion de version est apparue. Cette autre vision consiste à voir l’outil de gestion de version comme un outil permettant à chacun de travailler à son rythme, de façon désynchronisé des autres, puis d’offrir un moyen à ces développeurs de s’échanger leur travaux respectifs. C’est ce que l’on nomme la gestion de version décentralisée. »)

http://en.wikipedia.org/wiki/Apache_Gump (« Apache Gump is an open source Continuous Integration system, which aims to build and test all the open source Java projects, every night. Its aim is to make sure that all the projects are compatible, at both the API level and in terms of functionality matching specifications. It is hosted at gump.apache.org, and runs every night on the official Sun JVM….Gump was created by Sam Ruby, based on his experience in the Perl community. It was originally written in Java .Gump 3 is a complete rewrite in Python. It is the live version. Gump logo« )

Posted in Génie logiciel, Gestion de projet, Gestion de version, Intégration continue, python | 3 Comments »

Quelques outils et liens sur Wikipedia: wikimindmap, uncyclopedia, meta.wikimedia.org, ekopedia, http://fr.wikipedia.org/wiki/Special:Cite…etc

Posted by patrick sur juillet 6, 2007

Sur le fil RSS de « http://googlesystem.blogspot.com/ » j’ai découvert cette magnifique application « http://www.wikimindmap.org/ »

« According to Wikipedia, a mind map is « a diagram used to represent words, ideas, tasks or other items linked to and arranged radially around a central key word or idea. It is used to generate, visualize, structure and classify ideas, and as an aid in study, organization, problem solving, and decision making. »

This tool is a good way to visualize a complex Wikipedia article, become familiar with the most important concepts and explore related topics. »

Wikimindmap

Voilà ce que ça donne pour ‘python_language’

La map pour Python

Autres liens

http://meta.wikimedia.org/wiki/Main_Page (le site qui centralise les conseils, procédures et autres documents d’administration des différents projets)

http://www.ekopedia.org (« L’encyclopédie pratique traitant des techniques alternatives de vie. En écologie, nous connaissons le pourquoi. Voici donc comment répondre aux défis écologiques d’aujourd’hui et de demain »)

http://uncyclopedia.org/wiki/Main_Page (l’encyclopédie humoristique 🙂 )

http://wikitravel.org/fr/Accueil (« Wikitravel est un projet pour créer un guide de voyage libre, complet, à jour et fiable du monde entier. Nous avons déjà 1 578Wikivoyageurs du monde entier. Regardez l’Aide ou les Premiers pas pour voir comment vous pouvez éditer une page tout de suite » destinations, guides et autres articles écrits et édités par des )

http://species.wikimedia.org/wiki/Main_Page (« Wikispecies is an open, free directory of species. It covers Animalia, Plantae, Fungi, Bacteria, Archaea, Protista and all other forms of life. So far we have 104,031 articles »)

Voir la page principale « http://en.wikipedia.org/wiki/Main_Page » pour tous les projets frères/soeurs de Wikipedia.

Comme je découvre Wikipedia, voici une page importante qui m’avait échappé: elle indique comment citer les articles de Wikipedia. Pour produire une citation, aller sur la page http://fr.wikipedia.org/wiki/Special:Cite

Citer wikipedia

Une fois qu’on a produit la page de citations on choisit le format que l’on veut. Le style APA me plaît, c’est celui que je choisis.

Enfin voir la page http://en.wikipedia.org/wiki/Wikipedia:Guide_to_writing_better_articles qui donne des conseils pour écrire de meilleurs articles.

Posted in google, python, wikipedia | Leave a Comment »

Administration sytème: les systèmes RAID et SMART, CNIL, AFSIN

Posted by patrick sur juillet 6, 2007

Quelques définitions sur le système RAID (Redundant Array of Independent Disks, « matrice redondante de disques indépendants »). Je m’intéresse à ce sujet car le serveur GNU/Linux sur le lequel j’ai travaillé était équipé en RAID1.

http://fr.wikipedia.org/wiki/RAID_informatique (« En informatique, le mot RAID désigne une technologie permettant de stocker des données sur de multiples disques durs, en général de manière redondante, afin d’améliorer certaines caractéristiques essentielles de l’ensemble en fonction du type de RAID choisi, qu’il s’agisse de la tolérance aux pannes, de l’intégrité des données, ou des performances de l’ensemble.

RAID était à l’origine l’acronyme de Redundant Array of Inexpensive Disks, ce qui signifie « matrice redondante de disques bons marchés ». Aujourd’hui, le mot est devenu l’acronyme de Redundant Array of Independent Disks, ce qui signifie « matrice redondante de disques indépendants », car les disques durs sont bien meilleurs marchés qu’à l’époque.

Depuis son implémentation originale, la particularité principale de l’architecture RAID est sa capacité à combiner de nombreux périphériques de stockage bons marchés et d’une technologie courante dans une matrice unique, de sorte que ce groupement offre une capacité, une fiabilité et/ou des performances accrues, et ce pour un coût largement inférieur à un périphérique de stockage unique équivalent exploitant des technologies de pointe. L’architecture RAID s’oppose donc à l’architecture SLED (Single Large Expensive Disk), qui est fondée sur l’utilisation d’un seul et même disque dur de grande capacité, et donc d’un prix élevé, car il doit non seulement pouvoir stocker beaucoup d’informations, mais il doit de plus être d’excellente qualité pour en garantir au mieux l’intégrité.

En effet, dans une architecture de type SLED, la bonne conservation des données est dépendante de la moindre défaillance du disque dur. Lorsqu’une panne survient, non seulement le système est inexploitable le temps du remplacement du matériel défectueux, mais la seule manière de récupérer les données est de procéder à une restauration de la dernière sauvegarde, ce qui peut prendre plusieurs heures durant lesquelles le système est toujours inutilisable.

Si un tel temps d’inactivité est acceptable pour l’ordinateur d’un particulier, il est en revanche rédhibitoire pour le système informatique d’une entreprise, pour qui une telle panne peut avoir des conséquences non négligeables sur sa santé financière. L’utilisation d’une architecture RAID, du moins dans la plupart de ses niveaux fonctionnels, permet justement d’apporter une réponse à ces besoins car non seulement la défaillance d’un des disques de la grappe ne gêne pas le fonctionnement des autres disques, ce qui permet au système de continuer de fonctionner, mais de surcroît, une fois le disque en panne échangé, son contenu est reconstruit à partir des autres disques pendant le fonctionnement normal du système. Ainsi, l’activité de l’entreprise continue de façon ininterrompue et transparente pendant toute la durée de l’incident. »

Dans le cas de l’entreprise dans laquelle je travaillais la contrainte était plus forte puisqu’on prévoyait un crash des 2 disques en RAID1. Il fallait donc prévoir 2 autres disques RAID1 en secours.

« Miroitage (mirroring)

Le miroitage (mirroring en anglais) consiste à utiliser plusieurs unités de stockage de données et à stocker des données identiques sur chacune. Ainsi, chaque unité contient à tout moment exactement les mêmes données que les autres, on parle alors de disques miroirs, d’où l’utilisation du mot « miroitage ». Les modifications des données se font de manière simultanée sur toutes les unités de stockage, ainsi, en cas de panne d’une unité de stockage, les données sont toujours accessibles sur les unités restantes. Cette configuration pénalise légèrement les performances, mais a surtout l’inconvénient d’être particulièrement onéreuse, la fiabilité de l’ensemble étant directement proportionnelle au nombre d’unités de stockage. Lors de la défaillance de l’un des disques, le contrôleur RAID désactive, de manière transparente pour l’accès aux données, le disque incriminé. Une fois le disque défectueux remplacé, le contrôleur RAID reconstitue, soit automatiquement, soit sur intervention manuelle, le miroir. Une fois la synchronisation effectuée, le RAID retrouve son niveau initial de redondance. Mathématiquement, l’espérance de vie d’un système RAID 1 est 1,5 supérieure à celle d’un système sans RAID. »

Pour faire remonter les informations de dysfonctionnement et d’après ce que j’ai vu hier, on peut utiliser 2 utilitaires (smartctl and smartd) du package smartmontools (« The smartmontools package contains two utility programs (smartctl and smartd) to control and monitor storage systems using the Self-Monitoring, Analysis and Reporting Technology System (SMART) built into most modern ATA and SCSI hard disks. In many cases, these utilities will provide advanced warning of disk degradation and failure »)

Liens

  • http://www.linuxjournal.com/article/6983 (« it’s a given that all disks eventually die, and it’s easy to see why. The platters in a modern disk drive rotate more than a hundred times per second, maintaining submicron tolerances between the disk heads and the magnetic media that store data. Often they run 24/7 in dusty, overheated environments, thrashing on heavily loaded or poorly managed machines. So, it’s not surprising that experienced users are all too familiar with the symptoms of a dying disk. Strange things start happening. Inscrutable kernel error messages cover the console and then the system becomes unstable and locks up. Often, entire days are lost repeating recent work, re-installing the OS and trying to recover data. Even if you have a recent backup, sudden disk failure is a minor catastrophe. Many users and system administrators don’t know that Self-Monitoring, Analysis and Reporting Technology systems (SMART) are built in to most modern ATA and SCSI hard disks. SMART disk drives internally monitor their own health and performance. In many cases, the disk itself provides advance warning that something is wrong, helping to avoid the scenario described above. Most implementations of SMART also allow users to perform self-tests on the disk and to monitor a number of performance and reliability attributes« )
  • http://fr.wikipedia.org/wiki/Self-Monitoring%2C_Analysis_and_Reporting_Technology (« Self-Monitoring, Analysis, and Reporting Technology, ou S.M.A.R.T., (littéralement Technologie d’Auto-surveillance, d’Analyse et de Rapport) est un système de surveillance du disque dur d’un ordinateur. Il permet de faire un diagnostic selon plusieurs indicateurs de fiabilité dans le but d’anticiper les erreurs sur le disque dur…Les pannes mécaniques, qui sont des défaillances prévisibles, représentent 60 % des pannes de disque[1]. Le but du système S.M.A.R.T. est de prévenir l’utilisateur ou l’administrateur système de l’imminence d’une panne de disque alors qu’il reste encore du temps pour agir – comme par exemple copier les données sur un disque de remplacement. Environ 30 % des défaillances peuvent être prévues par le système S.M.A.R.T… D’un point de vue légal, le terme S.M.A.R.T. ne fait référence qu’à une méthode de communication entre les capteurs électromécaniques internes d’un disque dur et l’ordinateur hôte – donc un fabriquant de disque dur peut inclure un capteur pour uniquement un attribut physique et promouvoir ensuite le produit comme compatible S.M.A.R.T. Par exemple, un fabricant peut déclarer supporter la technologie S.M.A.R.T. mais ne pas inclure de capteur de température, capteur dont le consommateur est raisonnablement en droit d’attendre la présence, étant donné que la température est un paramètre crucial dans la prévision des défaillances (la fiabilité est typiquement proportionnelle à l’inverse de la température). Il se peut que certaines cartes mères compatibles S.M.A.R.T. ou certains logiciels associés ne puissent pas communiquer avec certains disques certifiés S.M.A.R.T. en fonction du type d’interface. Peu de disques externes connectés via USB ou FireWire envoient correctement les données S.M.A.R.T. par l’intermédiaire de ces interfaces. Étant donné le grand nombre de manières de connecter un disque dur (SCSI, Fibre Channel, ATA, SATA, etc.), il est difficile de savoir à l’avance si les rapports S.M.A.R.T. fonctionneront correctement ou pas. Même avec le disque dur et l’interface supportant S.M.A.R.T., les données peuvent ne pas être transmises correctement au système d’exploitation de l’ordinateur. Certains contrôleurs de disques peuvent dupliquer toutes les opérations d’écriture sur un deuxième disque de sauvegarde en temps réel. Cette technique est connue sous le nom de RAID 1 ou RAID mirroring car le second disque est une image miroir du premier. Cependant, de nombreux programmes conçus pour analyser les changements de comportement du disque et pour transmettre les alertes S.M.A.R.T. à l’utilisateur ne fonctionnent pas quand le système est configuré en RAID, parce que, dans les conditions normales de fonctionnement de l’architecture RAID, l’ordinateur n’est pas autorisé à « voir » (ou à accéder directement) les différents disques physiques, il est seulement autorisé à « voir » les volumes logiques à travers le sous-système RAID »).
  • http://smartlinux.sourceforge.net/smart/index.php (« This site contains information about S.M.A.R.T (Self-Monitoring, Analysis and Reporting Technology) – a standard that automatically monitors a disk drive’s health and report potential problems »)
  • http://www.afsin.org/ (« Association francophone des Spécialistes de l’Investigation Numérique. Notre Association Internationale a pour objet de développer une réflexion permanente en langue française sur l’investigation numérique, en tous domaines et en toutes circonstances, ainsi que sous tous ses aspects scientifiques, techniques, philosophiques, déontologiques, méthodologiques, économiques, juridiques, évolutifs et comparatifs avec les autres pays… L’AFSIN a pour vocation d’établir un dialogue constant entre les différents participants à l’investigation numérique, tels que techniciens, enquêteurs, juristes, magistrats… La première action de l’Association est de lancer plusieurs études par l’intermédiaire de son Comité Scientifique (récupération de données sur les téléphones GSM !!, récupération des méta-données, définition et termes de francisation, façons diverses de faire une « image » de disque, outillage utilisé, etc…). »)
  • http://fr.wikipedia.org/wiki/CNIL (« La Commission nationale de l’informatique et des libertés (CNIL) est une autorité administrative indépendante française chargée de veiller à la protection des données à caractère personnel et de la vie privée. Elle a été créée par la loi n° 78-17 du 6 janvier 1978 relative à l informatique, aux fichiers et aux libertés...La CNIL a été créé en 1978, suite au scandale du projet SAFARI (Système Automatisé pour les Fichiers Administratifs et le Répertoire des Individus), qui visait à interconnecter les fichiers nominatifs de l’administration française, notamment par le biais du numéro INSEE. La révélation de ce projet, le 21 mars 1974 par le quotidien le Monde, avait entraîné une vive opposition populaire, et la création de la Commission Nationale de l’Informatique et des Libertés quelques années plus tard.)

Posted in Administration système, Récupération de données | Leave a Comment »

Admin système, récupération de données: TestDisk, Photorec, Ping (Partimage Is Not Ghost), dd, netcat (nc)…etc

Posted by patrick sur juillet 5, 2007

Comme depuis 1 an je suis confronté à des problèmes de sauvegarde et de restauration aussi bien en environnement professionnel (je ne suis pourtant pas administrateur système) que personnel( les gens qui pensent que je fais des sauvegardes toute la journée 🙂 ), je vais étudier le problème…qui est bien vaste.

Je commence par TestDisk car je viens de recevoir un courriel de la liste http://linuxfr.org qui mentionne son existence.

http://www.cgsecurity.org/wiki/TestDisk («  est un logiciel Open Source distribué sous licence GPL (GNU Public License). TestDisk est un logiciel performant de récupération de données! Il a été conçu à l’origine pour aider à la récupération des partitions perdues, la réparation des tables des partitions corrompues quand ces symptômes ont été causés par des logiciels défectueux, certains types de virus ou des erreurs humaines (tel que l’effacement accidentel de la Table des Partitions »).

http://www.cgsecurity.org/wiki/Monitoring_SMART_FR (« Self-Monitoring, Analysis and Reporting Technology system). Il est possible de contrôler et surveiller les systèmes de stockage en utilisant la technologie SMART (Self-Monitoring, Analysis and Reporting Technology system) intégré dans les disques durs ATA et SCSI.Dans le but d’anticiper les pannes, la technologie SMART surveille et informe de l’état de certains indicateurs de fiabilité comme la température, le nombre de secteurs réalloués, les erreurs de localisation des secteurs et le temps cumulé d’utilisation.

  • Utiliser un logiciel pour surveiller les informations SMART afin de détecter les problèmes physiques.
    • smartmontools — logiciel opensource pour Windows, Linux, FreeBSD, NetBSD, OpenBSD, Solaris, Darwin, OS/2.
    • SMARTReporter — logiciel opensource pour Apple Macintosh
  • Si le disque est connecté via USB ou FireWire, les informations SMART peuvent ne pas être rapportés. Si c’est le cas, il est conseillé d’utiliser une connexion directe de type IDE, SCSI, SATA… »

http://www.cgsecurity.org/wiki/PhotoRec («  PhotoRec is file data recovery software designed to recover lost files including video, documents and archives from Hard Disks and CDRom and lost pictures (thus, its ‘Photo Recovery’ name) from digital camera memory. PhotoRec ignores the filesystem and goes after the underlying data, so it will still work even if your media’s filesystem has been severely damaged or re-formatted. PhotoRec is free, this open source multi-platform application is distributed under GNU Public License. PhotoRec is a companion program to TestDisk, an app for recovering lost partitions on a wide variety of filesystems and making non-bootable disks bootable again. You can download them from this link. PhotoRec searches known file header and because there is no data fragmentation (usually), it can recover the whole file. Photorec recognises numerous file format including ZIP, Office, PDF, HTML, JPEG and various graphics file formats. The whole list of file formats recovered by PhotoRec contains more than 80 file extensions. »)

http://www.windowsdream.com/ping/download.html (« PING (Partimage Is Not Ghost) Backup and Restore Disk Partitions. PING is a live Linux ISO, based on the excellent Linux From Scratch (LFS) documentation. It can be burnt on a CD and booted, or integrated into a PXE / RIS environment. Several tools have been added and written, so to make this ISO the perfect choice to backup and restore whole partitions, an easy way. It sounds like Symantec Ghost(tm), but has even better features, and is totally free« )

http://www.windowsdream.com/winner.html (« WINNER is a different way to set up a RIS Server. Basically, it gives you the possibility to deploy an unattended installation of Windows XP over a LAN, but has impressive specificities. Amongst them, a WINNER distribution can range from a minimalist Linux set (50 Mo) to a complete set of files (2 Go) — both of them leading to a similar, complete, Windows installation.« )

http://fr.wikipedia.org/wiki/Remote_Installation_Services (« Les Services d’installation à distance (Remote Installation Services ou RIS) est une fonctionnalité pour serveur fournit par Microsoft qui permet à des ordinateurs dont le BIOS prend en charge le Preboot eXecution Environment (PXE) d’exécuter de façon distante des variables d’environnement de démarrage…Il est possible d’installer ou booter d’autres systèmes d’exploitation grâce au RIS, par exemple une distribution GNU/Linux au travers du Linux Terminal Server Project…Le RIS a été remplacé par « Windows Deployment Services » (WDS) dans le Service Pack 2 de Windows Server 2003 et Windows Vista.« )

http://fr.wikipedia.org/wiki/Ghost_%28informatique%29 (« En informatique, Ghost (General Hardware Oriented System Transfer) est un logiciel, à l’origine produit par Binary Research, mais racheté par Symantec en 1998, pour cloner un disque dur (copie physique), ou plus spécifiquement, de cloner chaque partition d’un disque dur (copie logique). Le cryptage AES (Standard de chiffrement avancé) est aussi supporté pour préserver la confidentialité des sauvegardes. Ghost inclut aussi un Fdisk amélioré. L’image obtenue peut notamment être utilisée :

  • comme une sauvegarde pour restaurer l’état du disque au moment de la création de l’image
  • comme modèle pour réaliser un clonage de disque

Le concurrent direct de Ghost est Acronis True Image (commercial) , souvent considéré comme plus complet et simple d’utilisation.

Remarque: Depuis peu (2004) il existe PING (Partimage Is Not Ghost) qui n’est ni un produit commercial ni un logiciel open source.

Le terme « ghost » tend à se généraliser pour désigner toute image d’un support informatique ou d’un système informatique faite par un logiciel de sauvegarde. Dans le jargon informatique, le néologisme « ghoster un PC » est apparu. Il est synonyme de cloner, c’est à dire dupliquer le disque dur d’un PC. L’intérêt de ghoster un PC est de ne pas avoir besoin de réinstaller chaque logiciel un par un, ce qui est long et fastidieux pour la (ou les) personne(s) qui installe(nt) ces logiciels. Ghoster un PC est rapide et nécessite beaucoup moins de compétences; il reste cependant à personaliser la machine clonée en modifiant son nom et son adresse IP à l’issue du clonage. »

http://en.wikipedia.org/wiki/Dd_%28Unix%29 (« dd is a common UNIX program whose primary purpose is the low-level copying and conversion of files. The title of the UNIX sixth edition manual page of May 1975 was dd – convert and copy a file, and some have suggested that since « cc » was already in use as the code for the CCompiler, « dd » was used instead; in any case, DD is an acronym for « data definition » in IBM JCL (to which the command’s syntax bears a strong resemblance) and the name and syntax of the command is generally presumed to be a bit of gallows humor. » )

To create a zipped hard drive backup image:

# dd if=/dev/hda | gzip > /mnt/hdb1/system_drive_backup.img.gz

Here dd is making an image of the first harddrive, and piping it through the gzip compression program. The compressed image is then placed in a file on a separate drive. To reverse the process:

# gzip -dc /mnt/hdb1/system_drive_backup.img.gz | dd of=/dev/hda

Here, gzip is decompressing (the -d switch) the file, sending the results to stdout (the -c switch), which are piped to dd, and then written to /dev/hda.

To create an ISO image file from a CD. Insert the source cd and unmount it first if auto CD mount is enabled, this is to improve performance by preventing random access to the mounted filesystem.

dd if=/dev/cdrom of=/tmp/image.iso bs=2k

Note: The device might also be called /dev/dvd or /dev/scd0 (for a SCSI-drive).

To create an image file named floppy.img of a floppy disk in the drive whose block-device name is /dev/fd0 (as the first floppy device is on Linux), one may invoke dd in the following way:

dd if=/dev/fd0 of=floppy.img

Or to copy the img file back to a floppy:

dd if=floppy.img of=/dev/fd0 bs=16k

To create a file with name reallylargefile with the size of 1 GB, filled with random data, do this (1G = 1073741824, 1073741824 / 512 = 2097152 (the default block size is 512)):

dd if=/dev/random of=reallylargefile count=2097152

or faster but less cryptographicly secure

dd if=/dev/urandom of=reallylargefile count=2097152

To fill the file with NULL characters, use /dev/zero instead of /dev/random. This can be used to mount a filesystem if you have a FAT32 device, but need the flexibility of EXT2 – as follows to create a 10GB image:

dd if=/dev/zero of=my.new.virtual.harddisk bs=1k count=10MB
mke2fs my.new.virtual.harddisk (reply yes when it says it’s not a block device)
mkdir /mnt/virtual
mount -o loop my.new.virtual.harddisk /mnt/virtual/"

http://www.linuxquestions.org/questions/showthread.php?p=1848006#post1848006 (liste impressionnante d’utilisation de la commande ‘dd’)

http://www.softpanorama.org/Tools/dd.shtml (idem liste impressionnante d’utilisation de la commande ‘dd’:

slave% nc -l -p 9000 | dd of=/dev/sda (Replace /dev/sda with actual drive on your slave machine)

This will listen at port 9000 and whatever it gets at port 9000 will hand over to dd command and dd will simply write that to on slave harddrive (sda) bit by bit. Here I am assuming dd and netcat (nc) are available either through floppy (/mnt/floppy/nc or through /mnt/sources/mystuff/nc). In case of floppy you need to mount floppy first using command:
mount /dev/fd0 /mnt/floppy
On Master machine:
Now Login on master linux box and run following command. (It is advisable that Master Linux box should be in calm state , i.e no major jobs running on the machine). This command below will read master disk bit by bit and throw this bit stream to netcat command which is connected to netcat command at port 9000 on <slave> box.

master% dd if=/dev/sda | nc 192.168.0.254 9000

That’s it. You may have to wait for long time depending upon network speed and size of your harddrive. Typically 36GB drive may take 50 minutes over 100Mbps link. Again rather than cloning complete drive we can clone only relevant partitions and MBR only. That will make cloning much faster like we saw in above section »)

http://www.sweetnam.eu/index.php/Using_Netcat_for_Backup (« Providing you have netcat installed, on the destination machine execute the following command:

nc -l -p 6666 > filename.tar.bz2

This creates a listening socket on port 6666 with the filename specified above. We now need to setup the source machine to dump whatever directories or filesystems you want to send to the destination machine. So on the source you can issue the following command:

tar jlcvPpf - / > /dev/tcp/192.168.0.2/6666

In the example above 192.168.0.2 is the address of the destination address and the forward slash indicates that it is the entire filesystem to be backed up. You can easily change this for example to tar jlcvPpf – /var/www > /dev/tcp/192.168.0.2/6666 to backup the /var/www directory. If there is no /dev/tcp it is possible to use netcat on both ends

tar jlcPpf - / | nc 192.168.0.2 6666")

http://m.nu/program/util/netcat/netcat.html (« Netcat is a tool that every security professional should be aware of and possibly have in their ‘security tool box’. In May/June of 2000, insecure.org conducted a survey of 1200 Nmap users from the Nmap-hackers mailing list to determine their favorite security tools. Netcat was the second most popular tool, not including Nmap. A quick search on securityportal (www.securityportal.com) found 166 matches of netcat. Most of the matches describe or use netcat in some way. Netcat is a utility that is able to write and read data across TCP and UDP network connections. If you are responsible for network or system security it essential that you understand the capabilities of netcat.Netcat should not be installed unless you have authority to do so. Never install any executable unless you can trust the providor. If possible review the source and compile it yourself. To be safe only use netcat in a test environment. »..Nous voilà avertis ! Et voila des commandes bien puissantes: « 

Remote command prompt anyone?

On a Windows NT server issue the following command in the directory that contains netcat:

nc -l -p1234 -d -e cmd.exe –L

This –l puts netcat into listen mode, the -p1234 tells netcat to use port 1234, the –d allows netcat to run detached from the console, the –e cmd.exe tells netcat to execute the cmd.exe program when a connection is made, and the –L will restart Netcat with the same command line when the connection is terminated.

On the client system issue the following command:

nc destination 1234

This command causes netcat to connect to the server named destination on port 1234. Immediately you are given a console connection to the destination server. Be careful! To exit the remote console session type:

exit

You will be returned to your own console and will be able to reconnect to the destination server because netcat was started on the destination server with the –L option.

Sur GNU/Linux: (http://linuxfr.org/forums/26/16634.html)

Coté serveur:
——————
$> nc -u -l -p -e /bin/bash

Coté client:
—————
$> echo | nc -u <serveur IP> -w1

FTP & drive mapping blocked?

To receive a file named newfile on the destination system start netcat with the following command:

nc –l –p 1234 >newfile

On the source system send a file named origfile to the destination system with the following command:

nc destination 1234 <origfile

Issue a ^C on the source system and your done. Be sure to check the file to be sure it is the same size as the original. »)
Liens:

http://fr.wikipedia.org/wiki/Disques_durs (« Le disque dur ou Hard Disk Drive est une mémoire de masse magnétique. Il a remplacé efficacement les tambours (aujourd’hui obsolètes) et les bandes, qui sont utilisées de nos jours uniquement pour l’archivage et la sauvegarde. »)

http://www.cgsecurity.org/wiki/Articles

  1. PhotoRec versus Foremost: Récupération de fichiers (Juin 2006)
  2. PhotoRec: Récupération de fichiers dissimulés sur un cdrom (Juin 2007)

http://fr.wikipedia.org/wiki/Sauvegarde (« En informatique, la sauvegarde (backup en anglais) est l‘opération qui consiste à dupliquer et à mettre en sécurité les données contenues dans un système informatique. Par extension et par emprunt à l’anglais (to save), ce mot s’applique à tout enregistrement d’information sur un support permanent (par ex. l’écriture sur disque dur d’informations en mémoire vive). Dans ce sens, il est synonyme de « stockage d’information ». Mais le sens premier se rapproche de celui d’archivage, de conservation. »… »La sauvegarde s’inscrit dans une démarche plus globale qui consiste à assurer la continuité d’activité d’un système informatique ou, en cas de défaillance, son redémarrage le plus vite possible. Cette démarche est souvent formalisée dans un document qui peut porter des noms divers, par exemple le « PRA » (plan de reprise d’activité) ou le « PS » (plan de secours), et qui fait appel soit à des automatismes (ex. donner l’alerte en cas de coupure de courant ou de perte d’accès à une unité de stockage) soit à des gestes manuels (ex. remplacer des bandes magnétiques défectueuses). La tendance est à l’automatisation, réputée plus sûre dans les situations d’urgence que les opérations manuelles. »

http://fr.wikipedia.org/wiki/Master_boot_record (« Le Master Boot Record ou MBR Zone amorce« ) est le nom donné au premier secteur adressable d’un disque dur (cylindre 0, tête 0 et secteur 1, ou secteur 0 en adressage logique) dans le cadre d’un partitionnement Intel. Sa taille est de 512 octets. Le MBR contient la table des partitions (les 4 partitions primaires) du disque dur. Il contient également une routine d’amorçage dont le but est de charger le système d’exploitation (ou le boot loader/chargeur d’amorçage s’il existe) présent sur la partition active.« )

http://en.wikipedia.org/wiki/ISO_image (« An ISO image (.iso) is a disk image of an ISO 9660 file system. More loosely, it refers to any optical disc image, even a UDF image. As is typical for disc images, in addition to the data files that are contained in the ISO image, it also contains all the filesystem metadata, (boot code, structures, and attributes). All of this information is contained in a single file. These properties make it an attractive alternative to physical media for the distribution of software that requires this additional information as it is simple to retrieve over the Internet. Some of the common uses include the distribution of operating systems, such as Linux or BSD systems, and LiveCDs. »… dd (Unix)Linux/UNIX built-in command doing low-level copy, including generating ISO image from a CD.

    • ISO files can be mounted directly in Linux with the single command: mount -o loop -t iso9660 filename.iso /mnt/iso (assuming the directory /mnt/iso exists).
    • ISO images can also be made in Linux with simple commands: mkisofs -J -o filename.iso directory name. Using -J preserves the Windows Joliet) extensions, meaning the data in the directory should be readable on Windows systems. »

http://en.wikipedia.org/wiki/ISO_Master (« ISO Master is an open source application for Linux and BSD for creating and modifying ISO9660 files (ISO images).The first version was released as a working beta in August 2006 – a GTK-based GUI for the newly developed bkisofs (a library for reading and writing ISO9960 files in user space, including Joliet, RockRidge, and El Torito extensions) »

http://en.wikipedia.org/wiki/Isolinux (« The SYSLINUX Project covers a suite of lightweight bootloaders, for starting up computers in the Linux operating system. It is the work of H. Peter Anvin, and consists of several separate systems:

  • the original SYSLINUX, used for booting from FAT filesystems (usually floppy discs);
  • ISOLINUX, used for booting from CD-ROM ISO 9660 filesystems;
  • PXELINUX, used for booting from a network server using the Pre-boot eXecution Environment (PXE) system;
  • EXTLINUX, used to boot from Linux ext2/ext3 filesystems;
  • MEMDISK, used to boot older operating systems like MS-DOS from these media;
  • two separate menu systems; and
  • a development environment for additional modules.

SYSLINUX is not normally used for booting full Linux installations since Linux is not normally installed on FAT filesystems. Instead, it is often used for boot or rescue floppy discs, or other lightweight systems. ISOLINUX is generally used by Linux LiveCD and bootable install CDs. »)

http://en.wikipedia.org/wiki/Netcat (« In computing, netcat is a network utility for reading from and writing to network connections on either TCP or UDP. It is designed in a thin and simple way, which makes it easy to incorporate in larger applications. Because of its versatility, netcat is also called the « TCP/IP Swiss Army knife« .Netcat was twice voted the fourth most useful network security tool in polls conducted by insecure.org on the nmap users mailing list[1]« )

http://fr.wikipedia.org/wiki/Administrateur_syst%C3%A8me (« Un administrateur système est un informaticien responsable des serveurs d’une organisation (entreprise, association, administration). Ses tâches comprennent l’installation, le paramétrage, le maintien, la mise à jour, l’évolution, la sauvegarde, la restauration, la planification, la supervision, le conseil, le support et la veille technologique dans le périmètre technique des matériels et logiciels de type serveur, principalement les systèmes d’exploitation. Il a parfois la tâche de l’administration du réseau et/ou de l’administration des bases de données dans des organisations de petite taille. Il travaille au sein d’une DSI (Direction des Systèmes d’Information) ou d’une SSII (Société de Services en Ingénierie Informatique).
Il intervient auprès du DSI (Directeur des systèmes d’information), des DBA (Database Administrator, administrateur de bases de données), des administrateurs réseau, des webmasters et apparentés, des développeurs, des responsables bureautique (postes de travail) et enfin des usagers.
« )

http://en.wikipedia.org/wiki/System_administrator

http://guides-info.org/linux/admin/outils_sauvegarde.php (« Sauvegarder… LA tache que beaucoup repoussent… jusqu’à ce qu’une fausse manip ou une panne matérielle le leur fasse, souvent chèrement, regretter. Heureusement pour les prévoyants, il est excessivement simple de sauvegarder un (des) dossier(s), une partition ou même un disque dur complet, qu’ils soient linux, windows ou autre« )

http://www.inference.phy.cam.ac.uk/saw27/notes/backup-hard-disk-partitions.html (« It’s often useful to make an image of either an entire hard disk or an entire partition. One reason is to duplicate an installed system onto another PC (probably over a network connection); another is to make a backup of your complete hard disk including every aspect of the installed operating systems, which you can restore if you have to replace your hard disk or if you screw things up. Typically it’s useful to be able to transfer these images over the network to another machine, although you may want to save images onto a different partition or hard disk…There is a open source Linux program called partimage which is similar to Ghost, but I prefer to make backups using basic tools which I know will always be to hand, and in a pure format which I understand. My preferred solution in some situations is to use raw linux commands. The backup technique uses linux, but you don’t have to have linux installed on your computer to do this, and you can use this technique to backup partitions containing any filesystem« )

dd if=/dev/hda1 bs=1k conv=sync,noerror | gzip -c | ssh -c blowfish user@hostname "dd of=filename.gz bs=1k"

This instructs dd to read the contents of /dev/hda1 (the first partition). conv=sync,noerror tells dd that if it can’t read a block due to a read error, then it should at least write something to its output of the correct length. Even if your hard disk exhibits no errors, remember that dd will read every single block, including any blocks which the OS avoids using because it has marked them as bad. So don’t be too surprised if dd seems to struggle to read some blocks. (But see the next section for a better way of handling this situation).

bs=1k sets the block size to be 1k. I’m not quite sure what the optimal value is, but it needs to be no larger the the block size for the disk, otherwise a bad block may mask the contents of a good one. 1k is a safe bet.

In the above example the output of dd is piped through gzip to compress it. We then pipe the compressed data stream over an ssh connection to another linux machine (which may also be running Knoppix – see Knoppix notes below). If you wanted to write straight to a local file, you could either just add of=filename to the first dd command (to write an uncompressed image), or if you want to compress it, just redirect the output of the gzip to a filename.

Continuing with our explanation, the -c blowfish option to ssh selects blowfish encryption which is much faster (useful since we’re sending tons of data) than the default. Finally another dd command is invoked on the remote machine to read the data stream and write it to a file there. Alternatively you could pipe it through gunzip -c and write it straight to a partition on the remote machine instead of to a file.

Note that, as long as its not compressed, you should be able to mount a file containing a single partition’s image using a loopback device in linux. (With a little more jiggery-pokery to find the correct offset, you can also mount partitions within a whole-disk image; see here).

Restoring partitions

The restore procedure is fairly similar. For example, on the machine with the image on it, you might do something like:

dd if=filename.gz | ssh -c blowfish root@deadhost "gunzip -c | dd of=/dev/hda1 bs=1k". This assumes you have linux (e.g. Knoppix) running on the target machine with an ssh server running. See ‘Knoppix tips’, below. Note that you should not include conv=sync,noerror in the restore dd – doing so can, in certain situations, corrupt the data being written, since it instructs dd not to wait for more data to arrive from the network or filesystem if a whole block isn’t available.

The partition needs to already exist before you do this, and needs to be large enough to take all the data. If it’s too big, that doesn’t matter, you’ll just be wasting space at the end. You should then be able to grow the filesystem to fill that extra space. For ext2 filesystems, try using the ext2resize tool. You may also be able to persuade the partition editing tool parted to do this, since it can handle resizing most filesystems.

Alternative to ssh

If you’re on a trusted network, you might think it silly to go to trouble of encrypting and unencrypting all that data with ssh. Yet these days your machines are probably not configured to allow rsh connections. nc (a.k.a. netcat) is one option here: it just sends raw streams of data across a network. On the destination machine you could run nc -l -p 10001 > imagefile to start a process which will listen on TCP port 10001 and dump everything it receives from the first thing to connect to it to imagefile. Then on the source machine, pipe the output of dd (or gz, or whatever) to nc remote 10001 where remote is the name or IP address of the destination machine.

File-level backup techniques

Backing up entire partitions or disks is most useful when replacating systems across hard disks or when backing up partitions containing operating systems which are otherwise hard to fully backup. For more every-day backups of your data, a file-level method is more appropriate. Here are some handy tools for doing backups over a network to a remote machine in various clever ways:

http://doc.ubuntu-fr.org/tutoriel/sauvegarder_home_avec_grsync ( Sauvegarder « /home » avec Grsync, l’interface graphique de rsync)

http://doc.ubuntu-fr.org/applications/sauvegarde_d_une_partition (« Sauvegarder une partition permet de restaurer, si besoin, l’intégralité du système de fichiers qu’elle contient au moment de la sauvegarde. Ce principe est souvent utilisé pour sauvegarder l’intégralité d’un système d’exploitation ( appelé aussi backup ) . Cela ne semble pas adapté à la sauvegarde de documents personnels où l’on préférera backup-manager« )

 

Posted in Administration système, GNU/Linux, Récupération de données | 1 Comment »

La commande shell ‘find’inetrafec

Posted by patrick sur juillet 5, 2007

Voilà des exemples d’utilisation de la commande ‘find’ qui me sont bien utiles quand j’établis un « état des lieux » sur une application:

Rappel: La commande find est récursive, c’est à dire où que vous tapiez, elle va aller scruter dans les répertoires et les sous répertoires de chaque répertoire et ceci de façon récursive.

http://en.wikipedia.org/wiki/Find (« The find program is a search utility, mostly found on Unix-like platforms. It searches through one or more directory tree(s) of a filesystem, locating files based on some user-specified criteria. By default, find returns all files below the current working directory. Further, find allows the user to specify an action to be taken on each matched file. Thus, it is an extremely powerful program for applying actions to many files. It also supports regexp matching. »)

Ici cela s’applique à une application Java:

// Pour compter le nombre de lignes java
find . -name *.java -exec cat {} \; | wc -l

// Pour avoir la liste des fichiers java : ça c’est du classique
find . -name *.java -print

// Pour effacer tous les fichiers core situés sous mon répertoire :
find . -name core -exec rm {} \;

// pour avoir une demande de confirmation avant l’exécution de rm, vous pouvez taper :
find . -name core -ok rm {}\;

// Pour connaître les derniers fichiers modifiés dans les 3 derniers jours dans toute l’arborescence (/), vous devez taper :
find / -mtime 3 -print

// Pour connaître dans toute l’arborescence, les fichiers dont la taille dépasse 1Mo (2000 blocs de 512Ko), vous devez taper :
find / -size 2000 -print

// Vous pouvez chercher dans toute l’arborescence, les fichiers ordinaires appartenant à reza, dont la permission est fixée à 755, on obtient :
find / -type f -user reza -perm 755 -print

// rechercher dans le répertoire courant tous les fichiers normaux (sans les répertoires, fichiers spéciaux), et rechercher dans ces fichiers tous ceux contenant la chaîne toto.
find . -type f -print | xargs grep toto

// Exemple plus sophistiqué
find . -name *.java | xargs egrep -e « msg » | egrep -e « \ ».+\ » »| sort| uniq > aMsgJava.txt

// Recherche de la chaîne « DB » dans des programmes php
find . -name *.php -print | xargs grep DB

// supprimer des répertoires subversion .svn
find . -name « .svn » -exec chmod -R +w {} \;
find . -name « .svn » -exec rm -R {} \;

Liens:

  • http://fr.wikipedia.org/wiki/Shell_%28informatique%29 (… »Les systèmes d’exploitation de type Unix, GNU/Linux par exemple, disposent le plus souvent d’un shell. Celui-ci est utilisable en conjonction avec un terminal (souvent virtuel). A l’origine, l’interpréteur de commandes par défaut était tcsh (et c’était le Bourne_shell sur les Unix originels), mais aujourd’hui Bash est le plus répandu. Sur les postes de travail, les shells (environnements) graphiques KDE et/ou Gnome sont les plus usités. Il existe d’autres interpréteurs de commandes, notamment zsh et rc. »)

Posted in Administration système | Tagué: , , , , | Leave a Comment »