viernes, 20 de mayo de 2016

Ember: Instalar Node.js/NPM sin Sudo

Requerimientos para instalar Ember:
  node -v
  # Tienes dos opciones para instalar NVM
  curl https://raw.githubusercontent.com/creationix/nvm/v0.12.1/install.sh | bash
  # wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.12.1/install.sh | bash
  source ~/.profile
  # Si no te funcionan los siguientes comandos, abre un terminal nuevo
  nvm ls-remote       # lista de versiones
  nvm install v4.4.4  # intalacion
  nvm current         # version Node NVM activado
  node -v             # version Node que esta siendo usada
  npm -v              # version NPM que esta siendo usada
  which node          # donde esta instalado Node

  # Ya podemos instalar los paquetes
  npm -g install ember-cli     # Install Ember-cli
  npm -g install bower         # Install bower package manager
  npm -g install phantomjs     # Install phantomJS (integration testing)

  ember new proyecto           # Creamos un nevo proyecto ember
  cd proyecto
  ember server                 # arrancamos el servidor

  # Si clonaramos un proyecto de git
  git clone git@github.com:...

  cd proyecto
  npm install                  # instalamos dependencias
  bower install
  ember server

  # para usar una version concreta de Node
  nvm use v4.4.4

lunes, 10 de agosto de 2015

Iframe

Asi nuestra aplicacion Rails admite peticiones de un iframe

  # config/application.rb 
  # Enable IFrame
  config.action_dispatch.default_headers = { 'X-Frame-Options' => 'ALLOWALL' }

Este es el codigo html del iframe

  <iframe width="100%" frameborder="0" src="http://nuestra.apprails/" height="400"></iframe> 

domingo, 2 de agosto de 2015

Instalar rbenv, ruby-build y bundler en Ubuntu

# instalamos dependencias
sudo apt-get update
sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev
# inatalamos rbenv
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

exec $SHELL
type rbenv #=> "rbenv is a function"
# instalamos ruby-build
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
# Listado de las versiones de ruby
$ rbenv install -l
# Instalamos ruby 2.2.2, lo designamos por defecto y lo comprobamos
rbenv install 2.2.2
rbenv global 2.2.2
ruby -v
# para evitar intalar la documentecion de la gemas
echo "gem: --no-ri --no-rdoc" > ~/.gemrc
# instalamos bundler
gem install bundler
# Repo rbenv https://github.com/sstephenson/rbenv
# Repo ruby-build https://github.com/sstephenson/ruby-build
# web bundler http://bundler.io/
# Recordatorio RVM, instalación y uso http://en-la-mina.blogspot.com/2012/01/recordatorio-rvm-instalacion-y-uso.html

martes, 13 de mayo de 2014

Aplicación de Datos: Python, Flask, pip y virtualenvs

Flask un micro framework para crear aplicaciones web en python. Usar pip para instalar Flask

$ pip install Flask

Crear directorio en donde pondremos archivos con código de la aplicación

$ mkdir mi-app

Adentro crear archivo llamado app.py, donde configuremos Flask y servira como backend de nuestro proyecto. Abrir app.py en un editor

from flask import Flask
app = Flask(__name__)

Configurar para hacer la raíz de tu sitio. Usaremos un archivo llamado 'index.html' para colocar la información. Tenemos que especificarlo en app.py

from flask import Flask
from flask import render_template
app = Flask(__name__)

@app.route("/")
def index():
  return render_template('index.html')

Crear directorio "templates" dentro del directorio de nuestro proyecto.

$ mkdir templates

Crear "index.html" dentro del directorio "templates" y colocarle cualquier texto.

¡Hola Mundo!

Volver a editar app.py y agregarle lo siguiente para poder levantar el servidor local de Flask

from flask import Flask
from flask import render_template
app = Flask(__name__)

@app.route("/")
def index():
  return render_template('index.html')

if __name__ == '__main__':
  app.run(
    host="0.0.0.0",
    port=8000,
    use_reloader=True,
    debug=True,
  )

Correr app.py en la linea de comandos. Mirar el resultado en un navegador en http://localhost:8000

$ python app.py

Comenzar nuevamente editando "index.html". Reemplazar el contenido por el esqueleto de un archivo HTML


<!--doctype html-->
<html lang="es"> 
  <head></head>
  <body> 
    <h1>Incendios en España entre 2004 y 2014</h1>
  </body>
</html>

Crear directorio para guardar archivos estáticos. Aqui guardaremos el CSV con nuestros datos. Descargalo

$ mkdir static

Abrir app.py en editor de texto. Usaremos libreria csv para acceder a nuestros datos y pasarle la lista de datos del csv a index.html

from flask import Flask
from flask import render_template
app = Flask(__name__)

csv_path = './static/incendios.csv'
csv_obj = csv.DictReader(open(csv_path, 'r'))
csv_list = list(csv_obj)

@app.route("/")
def index():
  return render_template('index.html',
     object_list=csv_list,
  )

if __name__ == '__main__':
  app.run(
    host="0.0.0.0",
    port=8000,
    use_reloader=True,
    debug=True,
  )

Guardar app.py y editar index.html. Colocar la lista del csv en el index.html. En linea de comandos correr app.py y visitar http://localhost:8000 nuevamente

 
<!--doctype html--> 
<html lang="es"> 
  <head></head> 
  <body> 
    <h1>Incendios en España entre 2004 y 2014</h1> 
    {{ object_list }} 
  </body>
</html>

Vamos a darle formato a los datos en index.html. Estamos usando el lenguaje de templating jinja de Flask

 
<!--doctype html--> 
<html lang="es"> 
  <head></head> 
  <body> 
  <h1>Incendios en España entre 2004 y 2014</h1>
  <table border=1 cellpadding=7>
    <tr>
      <th>IDPIF</th>
      <th>Superficie Forestal Quemada</th>
      <th>Fecha</th>
      <th>Muertos</th>
      <th>Heridos</th>
      <th>Comunidad</th>
      <th>Provincia</th>
      <th>Comarca</th>
      <th>Causa</th>
      <th>Perdidas</th>
    </tr>
    {% for obj in object_list %}
      <tr>
        <td><a href="{{ obj['IDPIF'] }}/">{{ obj['IDPIF'] }}</a></td>
        <td>{{ obj['SUPQUEMADA'] }}</td>
        <td>{{ obj['FECHA'] }}</td>
        <td>{{ obj['MUERTOS'] }}</td>
        <td>{{ obj['HERIDOS'] }}</td>
        <td>{{ obj['COMUNIDAD'].decode('UTF-8') }}</td>
        <td>{{ obj['PROVINCIA'].decode('UTF-8') }}</td>
        <td>{{ obj['COMARCA'].decode('UTF-8') }}</td>
        <td>{{ obj['CAUSA'].decode('UTF-8') }}</td>
        <td>{{ obj['PERDIDAS'] }}</td> 
      </tr>
    {% endfor %} 
  </table>
  </body>
</html>

Ahora página de detalles por incendio. Agregamos una nueva ruta en archivo "app.py"

@app.route('//')
def detail(number):
  return render_template('detail.html')

Agreguemos el template "detail.html". Editamos el archivo detail.html. Agregar algo simple. Y levantamos la página en el navegador con cualquier número. http://localhost:8000/2004210126/

¡Hola Detalle!

Buscamos el incendio. Conectamos el número en la URL con el número identificador real del incendio en el CSV. Editamos app.py y convertimos la lista que tenemos en algo donde el incendio sea fácilmente buscable por identificador.

Editamos la función detail en app.py para que conecte el número en la URL con el registro correspondiente. Quedaría:

import csv
from flask import Flask
from flask import render_template
app = Flask(__name__)

csv_path = './static/incendios.csv'
csv_obj = csv.DictReader(open(csv_path, 'r'))
csv_list = list(csv_obj)
csv_dict = dict([[o['IDPIF'], o] for o in csv_list])

@app.route("/")
def index():
  return render_template('index.html',
     object_list=csv_list,
  )

@app.route('//')
def detail(number):
  return render_template('detail.html',
    object=csv_dict[number],
  )

if __name__ == '__main__':
  app.run(
    host="0.0.0.0",
    port=8000,
    use_reloader=True,
    debug=True,
  )

Volver a editar detail.html para agregarle datos desde nuestro CSV


<!--doctype html-->
<html lang="es">
  <head> <meta name="Incendios en España" content="text/html;" http-equiv="content-type" charset="utf-8">
  </head>
  <body>
    <h1>{{ object['COMUNIDAD'].decode('UTF-8') }}</h1>
  </body>
</html>

Editar "index.html" para enlazar la página del incendio. En la tag table reemplazar la fila de

<td><a href="{{ obj['IDPIF'] }}/">{{ obj['IDPIF'] }}</a></td>

Agregar el resto de los campos del incendio en detail.html


<!--doctype html-->
<html lang="es">
<head>
  <meta name="Incendios en España" content="text/html;" http-equiv="content-type" charset="utf-8">
  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
  <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js?2"></script>
</head>
<body>
  <div id="map" style="width:100%; height:300px;"></div>
  <h1>Incendio de {{ object['COMUNIDAD'].decode('UTF-8') }}</h1>
  <p>En la comunidad {{ object['COMUNIDAD'].decode('UTF-8') }}, provincia {{ object['PROVINCIA'].decode('UTF-8') }}, comarca {{ object['COMARCA'].decode('UTF-8') }}, municipio {{ object['MUNICIPIO'].decode('UTF-8') }} se quemó una superficie forestal de {{ object['SUPQUEMADA'] }}. Hubieron {{ object['MUERTOS'] }} muertos y {{ object['HERIDOS'] }} heridos. Se detectó en la fecha {{ object['FECHA'] }}. Se pudo controlar en {{ object['TIME_CTRL'] }} minutos y extinguir en {{ object['TIME_EXT'] }} minutos. La causa del incendio fue {{ object['CAUSA'].decode('UTF-8') }}. En la extinción del incendio participaron {{ object['PERSONAL'] }} personas, {{ object['PESADOS'] }} vehiculos pesados y {{ object['AEREOS'] }} medios aereos.</p>
  <script type="text/javascript">
    var map = L.map('map').setView([{{ object['LATITUD'] }}, {{ object['LONGITUD'] }}], 16);
    var mapquestLayer = new L.TileLayer('http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: 'Data, imagery and map information provided by <a href="http://open.mapquest.co.uk" target="_blank">MapQuest</a>,<a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> and contributors.',
      subdomains: ['otile1','otile2','otile3','otile4']
    });
    map.addLayer(mapquestLayer);
    var marker = L.marker([{{ object['LATITUD'] }}, {{ object['LONGITUD'] }}]).addTo(map);
  </script>
</body>
</html>

Javascript. Ahora vamos a colocar un mapa con los incendios usando una libreria de Javascript llamada Leaflet. Primero hay que importarla en el archivo "index.html"


<head>
  <meta name="Incendios en España" content="text/html;" http-equiv="content-type" charset="utf-8">
  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
  <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js?2"></script> 
</head>
<body>
...
</body>

Crear un elemento HTML para el mapa


...
<body>
  <h1>Incendios en España entre 2004 y 2014</h1>
  <div id="map" style="width:100%; height:300px;"></div>
...
</body>

Y usar Leaflet para centrarlo en España. Inicializamos el mapa con las coordenadas de España y nivel de zoom


  <script type="text/javascript">
    var map = L.map('map').setView([40.2085,-3.713], 6);
    var mapquestLayer = new L.TileLayer('http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
        maxZoom: 18,
        attribution: 'Data, imagery and map information provided by <a href="http://open.mapquest.co.uk" target="_blank">MapQuest</a>,<a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> and contributors.',
        subdomains: ['otile1','otile2','otile3','otile4']
    });
    map.addLayer(mapquestLayer);
  </script>

Agregamos la capa de tiles desde mapquest, que utiliza open street map. Se le pasa la URL para las imagenes de tiles, el nivel máximo de zoom (18) y el texto sobre de donde vienen los mapas.


  <script type="text/javascript">
    var map = L.map('map').setView([40.2085,-3.713], 6);
    var mapquestLayer = new L.TileLayer('http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
        maxZoom: 18,
        attribution: 'Data, imagery and map information provided by <a href="http://open.mapquest.co.uk" target="_blank">MapQuest</a>,<a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> and contributors.',
        subdomains: ['otile1','otile2','otile3','otile4']
    });
  </script>

Le agregamos el layer al elemento del mapa


  <script type="text/javascript">
  ...
  map.addLayer(mapquestLayer);
  </script>

Transformar los datos del CSV que tenemos a GeoJSON. GeoJSON es un formato para guardar estructuras de datos geograficos junto a información no geografica


  <script type="text/javascript">
  ...
    var data = {
      "type": "FeatureCollection",
      "features": [
        {% for obj in object_list %}
        {
          "type": "Feature",
          "properties": {
            "causa": "{{ obj['CAUSA'].decode('UTF-8') }}",
            "id": "{{ obj['IDPIF'] }}"
          },
          "geometry": {
            "type": "Point",
            "coordinates": [{{ obj['LONGITUD'] }}, {{ obj['LATITUD'] }}]
          }
        }{% if not loop.last %},{% endif %}
        {% endfor %}
      ]
    };
    var dataLayer = L.geoJson(data);
    map.addLayer(dataLayer);
  </script>

Agregar una ventanita popup que muestre información sobre el incendio. Sustituir var dataLayer


  <script type="text/javascript">
  ...

    var dataLayer = L.geoJson(data, {
        onEachFeature: function(feature, layer) {
            layer.bindPopup(
              '<a href="' + feature.properties.id + '/">' +
                feature.properties.causa +
              '</a>')
        }
    });
    map.addLayer(dataLayer);
  </script>

Hacemos lo mismo en "detail.html" agregamos un mapa del incendio. Quedaria:


<!--doctype html-->
<html lang="es">
<head>
  <meta name="Incendios en España" content="text/html;" http-equiv="content-type" charset="utf-8">
  <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
  <script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js?2"></script>
</head>
<body>
  <div id="map" style="width:100%; height:300px;"></div>
  <h1>Incendio de {{ object['COMUNIDAD'].decode('UTF-8') }}</h1>
  <p>En la comunidad {{ object['COMUNIDAD'].decode('UTF-8') }}, provincia {{ object['PROVINCIA'].decode('UTF-8') }}, comarca {{ object['COMARCA'].decode('UTF-8') }}, municipio {{ object['MUNICIPIO'].decode('UTF-8') }} se quemó una superficie forestal de {{ object['SUPQUEMADA'] }}. Hubieron {{ object['MUERTOS'] }} muertos y {{ object['HERIDOS'] }} heridos. Se detectó en la fecha {{ object['FECHA'] }}. Se pudo controlar en {{ object['TIME_CTRL'] }} minutos y extinguir en {{ object['TIME_EXT'] }} minutos. La causa del incendio fue {{ object['CAUSA'].decode('UTF-8') }}. En la extinción del incendio participaron {{ object['PERSONAL'] }} personas, {{ object['PESADOS'] }} vehiculos pesados y {{ object['AEREOS'] }} medios aereos.</p>
  <script type="text/javascript">
    var map = L.map('map').setView([{{ object['LATITUD'] }}, {{ object['LONGITUD'] }}], 16);
    var mapquestLayer = new L.TileLayer('http://{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: 'Data, imagery and map information provided by <a href="http://open.mapquest.co.uk" target="_blank">MapQuest</a>,<a href="http://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> and contributors.',
      subdomains: ['otile1','otile2','otile3','otile4']
    });
    map.addLayer(mapquestLayer);
    var marker = L.marker([{{ object['LATITUD'] }}, {{ object['LONGITUD'] }}]).addTo(map);
  </script>
</body>
</html>




domingo, 20 de abril de 2014

Python, Django, pip y virtualenvs en Ubuntu

Manuales
  • Guía de aprendizaje de Python [web]
  • El libro de Django [pdf]
Instalamos entorno Python/Django [gdggranada.com]:
Ubuntu (12.04) ya trae Python (2.7), aun así comprobamos que está todo:

verdor@enlamina ~$ sudo apt-get install python-virtualenv python-pip python-dev sqlite3 python-sqlite build-essential
verdor@enlamina ~$ #sudo apt-get install python-imaging python-pythonmagick python-markdown python-textile python-docutils #parece que esto es opcional
  • pip es una herramienta para instalar y administrar Paquetes Python (¿RubyGem?)
  • virtualenvs o entornos virtuales (de Python) es un espacio completamente independiente de otros entornos virtuales y de los paquetes instalados globalmente en el sistema (¿RVM?) [Tutorial de Python virtualenv]
No realizar los siguientes pasos... Mejor usar pip y virtualenvs
Podemos instalar Django con apt-get de sistema...

verdor@enlamina ~$ sudo apt-get install python-django
...o bajar los repos...
verdor@enlamina ~$ git clone https://github.com/django/django.git
... o usar pip...
verdor@enlamina ~$ pip install Django==1.6.2 # Estable
verdor@enlamina ~$ # pip install https://www.djangoproject.com/download/1.7b1/tarball/ # version beta 1.7

Continuamos...
Preparamos el Entorno:
Actualizamos pip e instalamos virtualenv (se puede hace con sudo)

verdor@enlamina ~$ pip install --upgrade pip
verdor@enlamina ~$ pip install --upgrade virtualenv # --upgrade es opcional

Preparamos el entorno:

verdor@enlamina ~$ cd src
verdor@enlamina ~/src$ mkdir entorno
verdor@enlamina ~/src$ cd entorno
verdor@enlamina ~/src/entorno$ virtualenv env
New python executable in env/bin/python
Installing setuptools, pip...done.

Activamos el entorno:

verdor@enlamina ~/src/entorno$ source env/bin/activate
(env)verdor@enlamina ~/src/entorno$  # ojo con el prompt

Instalamos django 1.5:

(env)verdor@enlamina ~/src/entorno$ pip install django==1.5
Downloading/unpacking django==1.5
  Downloading Django-1.5.tar.gz (8.0MB): 8.0MB downloaded
...
Successfully installed django
Cleaning up...

Creamos un proyecto (luego distinguiremos entre proyecto y aplicación):

verdor@enlamina ~$ django-admin.py startproject mysite
verdor@enlamina ~$ cd mysite
verdor@enlamina/mysite ~$ python manage.py runserver
Validating models...

0 errors found
April 20, 2014 - 06:51:31
Django version 1.5, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Vamos a comprobar que arranca la aplicación en el navegador http://127.0.0.1:8000/, y esto es lo que vemos:

It worked!

Congratulations on your first Django-powered page.

Of course, you haven't actually done any work yet. Here's what to do next:
  • If you plan to use a database, edit the DATABASES setting in mysite/settings.py.
  • Start your first app by running python manage.py startapp [appname].
You're seeing this message because you have DEBUG = True in your Django settings file and you haven't configured any URLs. Get to work!

¿Y donde esta el código generado de mi proyecto?

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

  • miblog/: El Directorio externo que contiene nuestro projecto.
  • miblog/miblog: El directorio interno que sera el nombre que usaremos para importar el paquete.
  • manage.py: Una utilidad de línea de comandos para interactuar con nuestro proyecto(crear las tablas, iniciar el servidor...).
  • miblog/__init__.py: Un archivo vació requerido para que Python trate a este directorio como un paquete.
  • miblog/settings.py: Configuraciones para este proyecto de Django.
  • miblog/urls.py: La “tabla de contenidos” de nuestro proyecto.
  • miblog/wsgi.py: El archivo encargado de ser compatible con el servidor web.
Configuración del proyecto:
Editamos settings.py. Guias: maestrosdelweb.com django-en-cero-coma-i 1ªDjangoApp
Codificacion de caracteres:

#encoding:utf-8

Ruta del proyecto. Con ello creamos una nueva variable de configuración que guarda la ruta del proyecto, de manera que ahora podemos indicar el resto de rutas de forma relativa a la nueva variable. Además añadimos esta ruta al path de python lo que repercutirá en ventajas futuras.

# Identificando la ruta del proyecto
import os
PROJECT_PATH = os.path.dirname(os.path.realpath(__file__))

Configuramos la base de datos. Usamos sqlite3. También podríamos usar por fácilmente postgresql, mysql y oracle

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'mysite.db',                      # Or path to database file if using sqlite3.
        # The following settings are not used with sqlite3:
        'USER': '',
        'PASSWORD': '',
        'HOST': '',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
        'PORT': '',                      # Set to empty string for default.
    }
}

Otras variables:

TIME_ZONE = 'Europe/Madrid'
LANGUAGE_CODE = 'es-es'

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    'django.contrib.admindocs',
    # Esta es la aplicación que estamos haciendo
    'mysite',
)

Aplicaciones instaladas INSTALLED_APPS: Un proyecto en Django necesita de aplicaciones, algunas ya vienen configuradas de manera predeterminada. En nuestro proyecto usaremos la aplicación de administración y su documentación, estas ya vienen construidas, y también nuestra primera aplicación creada líneas arriba, llamada principal. Para habilitar estas aplicaciones debemos buscar la siguiente sección que se encuentra casi al final del archivo settings.py. Django tendra que crear las tablas de estas aplicaciones adames de las que necesite nuestra propia aplicación mysite.
El resto de configuraciones se iran modificando a medida que lo necesitemos.
Creación de la base de datos. (Ojo, si no esta cargado el envairoment no funcionara):

(env)verdor@enlamina ~/src/entorno/mysite$ python -c "import django; print(django.get_version())" # Prueba 
1.5
verdor@enlamina ~/src/entorno/mysite$ source ../env/bin/activate # Si falla lo cargamos así
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py sync #Creación BD
Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'verdor'): 
Email address: 
Password: 
Password (again): 
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

Configuramos las direcciones/rutas del proyecto. Fichero urls.py. Es solo descomentar algunas lineas:

from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'mysite.views.home', name='home'),
    #url(r'^mysite/', include('mysite.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
)

Arrancamos el servidor y ya podemos ir a la zona de administración http://127.0.0.1:8000/admin

(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py runserver

Este es un buen momento usar git y hacer un comit inicial y montar un repositorio en github
? Antes de seguir. Lo que hemos hecho es crear un proyeco. Un proyecto puede estar compuesto de múltiples aplicaciones (ejemplo las que vienen por defecto en INSTALLED_APPS), y una aplicación se puede integrar en múltiples proyectos.
Creamos una aplicación:
Vamos a realizar un blog

verdor@enlamina ~$ ~/src/entorno/mysite$ source ../env/bin/activate #Cargamos el entorno
(env)samu@sub ~/src/entorno/mysite$ python manage.py startapp blog #Creamos al aplicacion

Ahora tenemos los siguientes ficheros:

mysite/
    manage.py
    blog/
        __init__.py
        models.py
        tests.py
        views.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

Comenzamos con el modelo (ejemplo 1, ejemplo 2) (ORM). Editamos models.py:

from django.db import models

# Create your models here.
class Category(models.Model):
    name = models.CharField(max_length=200)

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    category = models.ForeignKey(Category)
    creation_date = models.DateTimeField(auto_now_add=True)

Antes de probar el modelo, hay que incluir la aplicación blog en el proyecto editando mysite/setting.py

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    'django.contrib.admindocs',
    # Esta es el proyecto
    'mysite',
    # Esta es aplicación
    'blog',
)

Una vez hecho esto ejecutamos el siguiente comando y comprobamos que se generan las consultas esperadas:

(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py sqlall blog
BEGIN;
CREATE TABLE "blog_category" (
    "id" integer NOT NULL PRIMARY KEY,
    "name" varchar(200) NOT NULL
)
;
CREATE TABLE "blog_post" (
    "id" integer NOT NULL PRIMARY KEY,
    "title" varchar(200) NOT NULL,
    "content" text NOT NULL,
    "category_id" integer NOT NULL REFERENCES "blog_category" ("id"),
    "creation_date" datetime NOT NULL
)
;
CREATE INDEX "blog_post_6f33f001" ON "blog_post" ("category_id");

COMMIT;

Ahora creamos las tablar realmente:

(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py syncdb
Creating tables ...
Creating table blog_category
Creating table blog_post
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

Toca el momento de crear las vistas. Editamos blog/views.py e importamos los modelos que vayamos a utilizar:

# Create your views here.
from django.shortcuts import render_to_response

from blog.models import Category
from blog.models import Post

Tambien en blog/views.py añadiremos las funciones que gestionan las peticiones que se hagan al servidor. Algo así como los controladores de RoR.

# Create your views here.
from django.shortcuts import render_to_response

from blog.models import Category
from blog.models import Post

# Vista para un post
# Show
# template/post.html
def one_post(request, idpost):
    post = Post.objects.get(id=idpost)
    
    return render_to_response(
        "post.html",
        {
            "post":post,
        },
    )

# Vista de un listado de posts
# Index
#template/home.html
def home(request):
    posts = Post.objects.order_by("-creation_date")
    
    return render_to_response(
        "home.html",
        {
            "posts":posts,
        },
    )

# Vista de un listado de posts filtrado por category
#template/home.html
def posts_by_category(request, idcategory):
    category = Category.objects.get(id=idcategory)
    posts = category.post_set.order_by("-creation_date")
    
    return render_to_response(
        "home.html",
        {
            "posts":posts,
        },
    )

Ahora creamos las plantillas. Lo que en RoR serian las vistas. Se estarán en la carpeta blog/templates/
Creamos blog/templates/base.html. Se usará de base para generar el resto de las plantillas. Las plantillas heredarán de base.html, y a través de etiqueta block base.html mostrara el código de las plantillas que hereden de esta:

#blog/templates/base.html
<!DOCTYPE html>
<html>
    <head>
    <title>{% block title %}{% endblock %}</title>
    </head>
    
    <body>
    {% block content %}{% endblock %}
    </body>
</html>

Creamos post.html

{% extends "base.html" %}

{% block title %}
    {{ post.title }}
{% endblock %}

{% block content %}
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
{% endblock %}

home.html

{% extends "base.html" %}

{% block title %}Mi blog{% endblock %}

{% block content %}
    
    {% for post in posts %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.content }}</p>
        <hr>
    {% endfor %}

{% endblock %}

Tenemos que indicar en al proyecto donde estan las plantillas, editamos TEMPLATE_DIRS de mysite/settinds.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.
    "../blog/templates",
)

Nos quedan crear las URLs de la aplicacion (las rutas). Lo primero indicar al proyecto que busque las URLs de la aplicacion blog. Editamos mysite/urls.py e indicamos que incluya las rutas de blog. Quedaria asi:

from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'mysite.views.home', name='home'),
    #url(r'^mysite/', include('mysite.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
    # Rutas de la aplicacion blog
    url(r'^', include('blog.urls')),
)

Ahora crearemos un fichero blog/urls.py de la aplicación. Debe quedar así:

from django.conf.urls import patterns, include, url

urlpatterns = patterns('',
    url(
         r'^post/(?P[0-9]+)/$',
         'blog.views.one_post', 
         name="one_post"),
    url(
         r'^category/(?P[0-9]+)/$',
         'blog.views.posts_by_category',
         name="posts_by_category"),
    url(
         r'^$',
         'blog.views.home',
         name='home'),
)

Por último vamos hacer accesibles nuestro modelos den blog desde el panel de adminición. Para ello vamos a añadir un fichero admin.py en el directorio blog indicándoselo. Debería quedar así:

from django.contrib import admin
from blog.models import Category
from blog.models import Post

admin.site.register(Post)
admin.site.register(Category)

Símplemente registramos los modelos en el panel de administración. Por último, vamos a ejecutar de nuevo el comando para sincronizar la base de datos, ya que Django Admin añadirá alguna tabla más:

(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py syncdb
Creating tables ...
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py runserver

Ya podemos introducir algún post por la zona de admin http://localhost:8000/admin/ y luego verlo http://localhost:8000/post/1/
Consola Django

(env)verdor@enlamina ~/src/entorno/mysite$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import django
>>> from blog.models import Post, Category
>>> Category.objects.all()
[, ]
>>> Category.objects.all()[0]

>>> Category.objects.all()[0].id
1
>>> Category.objects.all()[0].name
u'ruby'
>>> Category.objects.all()[1].name
u'lorem'
>>> 

Para que la salida de los objetos por la consola sea mas amigable, tendremos que añadir a los modelos los métodos "def __str__(self):" quedando el fichero bog/models.py de esta manera:

from django.db import models

# Create your models here.
class Category(models.Model):
    name = models.CharField(max_length=200)

    def __str__(self):
      return self.name


class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    category = models.ForeignKey(Category)
    creation_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
      return '%s %s' % (self.title, self.creation_date)

jueves, 17 de abril de 2014

Raspberry Pi: Desplegando aplicación Rails,RVM,Thin en nginx con Capistrano


Configuración en el servidor:

Instalación de RVM multi-usuario [script]:

pi@raspberrypi ~ $ sudo su
root@raspberrypi:/home/pi# curl -L get.rvm.io | bash -s stable
#source /etc/profile.d/rvm.sh
root@raspberrypi:/home/pi# source /etc/profile
root@raspberrypi:/home/pi# rvm requirements;
root@raspberrypi:/home/pi# apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion pkg-config
root@raspberrypi:/home/pi# rvm install 2.0.0

Tenemos que instalar Nginx. Esta explicado en la anterior entrada: Cambiando Apache por Nginx

Vamos a crear el usuario que realizara los deploy de capistrano. El aprovechamos para crear con un home diferente /var/deploy y alojar ahí las aplicaciones. Luego bloqueamos la contraseña, solo podremos logarnos y deployar a través de ssh.

root@raspberrypi:/home/pi# adduser --home /var/deploy deploy
root@raspberrypi:/home/pi# passwd -l deploy

Nos vamos ponernos como usuario deploy y lo configuramos para poder autenticarnos por ssh como el usuario deploy (explicado en entrada anterior):

root@raspberrypi:/home/pi# su - deploy
deploy@raspberrypi ~ $ pwd #comprobamos donde estamos y si es igual al HOME esperado
/var/deploy
deploy@raspberrypi ~ $ mkdir .ssh
deploy@raspberrypi ~ $ vim .ssh/authorized_keys #introducimos la llave publica a autorizar
Vamos a crear el gemset de nuestra aplicación y como instalaríamos thin:
deploy@raspberrypi ~ $ rvm use 2.0.0@showip --create
deploy@raspberrypi ~ $ rvm gemset create showip
deploy@raspberrypi ~ $ # gem install thin


Configuración en nuestra aplicación (entorno de desarrollo):

En el Gemfile añadimos capistrano y thin [ejemplo thin, ejemplo unicorn]:
# Use Capistrano for deployment
group :development do
  gem 'capistrano'
  gem "rvm-capistrano"
end

# Use Thin for production
gem 'thin', group: :production

Si no tenemos instalado ningún motor de Javascript en el servidor, tenemos que descomentar también la linea de therubyracer. Otra opción, instalar en el servidor nodejs.

Ejecutamos un bundle y comando para crear ficheros de capistrano:

$ bundle install
$ capify .
[add] writing './Capfile'
[add] writing './config/deploy.rb'
[done] capified!
Configuramos el fichero de /config/deploy.rb, (lo creamos si es necesario). En mi caso queda así:
require "rvm/capistrano"
#require "capistrano/ext/multistage"
require "bundler/capistrano"

#set :stages, %w(staging production) #Si queremos mas de un entorno

set :application, "showip"
set :repository,  "git@github.com:verdor/showip.git"

default_run_options[:pty] = true
ssh_options[:forward_agent] = true

# la versión de ruby tiene que estar instalada y el gemset existir
# antes del cap deploy:setup
set :rvm_ruby_string, 'ruby-2.0.0-p451@showip'
set :rvm_type, :system

set :scm, :git
set :git_shallow_clone, 1
server "192.168.1.10", :app, :web, :db, primary: true
#server "showip.tk", :app, :web, :db, primary: true

set :user, "deploy"
set :keep_releases, 5
set :use_sudo, false

#set :port, 22 #sustituye con el puerto que usas
# Capistrano's default location "/u/apps/#{application}"
set :deploy_to, "/var/#{user}/apps/#{application}"
set :deploy_via, :remote_cache

set :branch, "master"

after  "deploy:finalize_update" , "symlinks"
after  "deploy",                  "deploy:cleanup"

namespace :deploy do
  desc "Despues de ejecutar el setup subimos ficheros de configuracion"
  task :setup_config, roles: :app do
    #run "mkdir #{shared_path}/config"
    #run "#{try_sudo} mkdir #{shared_path}/config"
    top.upload("config/nginx.conf", "#{shared_path}/nginx.conf", via: :scp)
    top.upload("config/thin_config.yml", "#{shared_path}/thin_config.yml", via: :scp)
    top.upload("config/database.yml", "#{shared_path}/database.yml", via: :scp)
    #top.upload(".rvmrc", "#{shared_path}/.rvmrc", via: :scp)
    top.upload(".versions.conf", "#{shared_path}/.versions.conf", via: :scp)
    #sudo "mv #{shared_path}/config/nginx.conf /etc/nginx/sites-available/showip"
    #sudo "ln -nfs /etc/nginx/sites-available/showip /etc/nginx/sites-enabled/showip"
  end

  after "deploy:setup", "deploy:setup_config"
end

task :symlinks, roles: [:app] do
  run <<-CMD
    ln -s #{shared_path}/cache #{release_path}/public/;
    ln -s #{shared_path}/database.yml #{release_path}/config/;
    ln -s #{shared_path}/thin_config.yml #{release_path}/config/;
    ln -s #{shared_path}/.versions.conf #{release_path}/;
  CMD
end

namespace :deploy do
  desc "Start the Thin processes"
  task :start do
    run  <<-CMD
      cd #{current_path}; bundle exec thin start -C config/thin_config.yml
    CMD
  end

  desc "Stop the Thin processes"
  task :stop do
    run <<-CMD
      cd #{current_path}; bundle exec thin stop -C config/thin_config.yml
    CMD
  end

  desc "Restart the Thin processes"
  task :restart do
    run <<-CMD
      cd #{current_path}; bundle exec thin restart -C config/thin_config.yml
    CMD
  end
end
Un a vez hecho esto, queremos ver el listado de tareas capistrano:
verdor@enlamina ~$ cap -T
Creamos el fichero de configuración del servidor en nginx para nuestra aplicación:
upstream showip {
        server 127.0.0.1:3000;
}
server {
        listen       80;
        server_name  showip.pi showip.jeronima.tk showip.tk;

        root /var/deploy/apps/showip/current/public/;
        access_log /var/log/nginx/showip-access.log;
        error_log /var/log/nginx/showip-error.log;
        rewrite_log on;

        location ~ ^/assets/ {
                root /var/deploy/apps/showip/current/public;
                gzip_static on;
                expires 1y;
                add_header Cache-Control public;
                add_header ETag "";
                break;
        }

        location / {
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

                client_max_body_size 10m;
                client_body_buffer_size 128k;

                proxy_connect_timeout 90;
                proxy_send_timeout 90;
                proxy_read_timeout 90;

                proxy_buffer_size 4k;
                proxy_buffers 4 32k;
                proxy_busy_buffers_size 64k;
                proxy_temp_file_write_size 64k;

                proxy_redirect off;
                if (!-f $request_filename) {
                        proxy_pass http://showip;
                        break;
                }
        }

        if (-f $document_root/system/maintenance.html) {
                return 503;
        }
        error_page 503 @maintenance;
        location @maintenance {
                rewrite  ^(.*)$  /system/maintenance.html last;
                break;
        }

        error_page 500 502 503 504 /50x.html;
}
Escribimos nuestro fichero de configuracion del thin, pero al final no lo usamos y lo generamos con thin en el propio servidor, probar ejecutando thin -h:

---
chdir: /var/deploy/apps/showip/current
environment: production
address: 0.0.0.0
port: 3000
timeout: 30
log: /var/deploy/apps/showip/current/log/thin.log
pid: /var/deploy/apps/showip/current/tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
threadpool_size: 20
servers: 1
user: deploy
group: deploy
daemonize: true
Ahora tenemos que preparar el servidor con capistrano:

verdor@enlamina ~$ cap deploy:update
verdor@enlamina ~$ cap deploy:start

* Ojo, la aplicación no tiene base de datos, ni asset.



Más configuración en el servidor. WRAPPERS. Que wrappers.

Queremos que nuestra aplicación se inicie como un servicio más (init.d):

pi@raspberrypi ~ $ sudo su
root@raspberrypi:/home/pi# source /etc/profile #cargamos rvm
root@raspberrypi:/home/pi# rvm use ruby-2.0.0-p451@showip
root@raspberrypi:/home/pi# thin install
Installing thin service at /etc/init.d/thin ...
mkdir -p /etc/init.d
writing /etc/init.d/thin
chmod +x /etc/init.d/thin
mkdir -p /etc/thin

To configure thin to start at system boot:
on RedHat like systems:
  sudo /sbin/chkconfig --level 345 thin on
on Debian-like systems (Ubuntu):
  sudo /usr/sbin/update-rc.d -f thin defaults
on Gentoo:
  sudo rc-update add thin default

Then put your config files in /etc/thin

Genera el el fichero /etc/init.d/thin, mostramos como se crea, pero luego lo renombraremos y editaremos:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          thin
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      S 0 1 6
# Short-Description: thin initscript
# Description:       thin
### END INIT INFO

# Original author: Forrest Robertson

# Do NOT "set -e"

DAEMON=/usr/local/rvm/gems/ruby-2.0.0-p451@showip/bin/thin
SCRIPT_NAME=/etc/init.d/thin
CONFIG_PATH=/etc/thin

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

case "$1" in
  start)
        $DAEMON start --all $CONFIG_PATH
        ;;
  stop)
        $DAEMON stop --all $CONFIG_PATH
        ;;
  restart)
        $DAEMON restart --all $CONFIG_PATH
        ;;
  *)
        echo "Usage: $SCRIPT_NAME {start|stop|restart}" >&2
        exit 3
        ;;
esac

:
Si vamos a tener más de una aplicación que use thin, renombramos el fichero /etc/init.d/thin, en nuestro caso por /etc/init.d/showip y modificamos...

SCRIPT_NAME=/etc/init.d/showip
CONFIG_PATH=/etc/showip #var/deploy/showip
Lo renombramos y ponemos en el arranque:

root@raspberrypi:~# mv /etc/init.d/thin /etc/init.d/showip
root@raspberrypi:~# sudo /usr/sbin/update-rc.d -f showip defaults
Generamos la configuracion del thin para nuestra aplicacion showip

root@raspberrypi:~# thin config -C /etc/thin/showip.yml -c /var/deploy/apps/showip/current --servers 1 -p 3000
Wrote configuration to /etc/thin/showip.yml
Editamos el fichero del config /etc/thin/showip.yml para ver si le damos algun retoque:

---
chdir: /var/deploy/apps/showip/current
environment: production
address: 0.0.0.0
port: 3000
timeout: 30
log: log/thin.log
pid: /var/deploy/apps/showip/current/tmp/pids/thin.pid
max_conns: 1024
max_persistent_conns: 100
require: []
wait: 30
threadpool_size: 20
servers: 1
user: deploy
group: deploy
daemonize: true
Generamos el wrapper de RVM ya que la ruta /usr/local/rvm/gems/ruby-2.0.0-p451@showip/bin/thin no nos acaba de funcionar, despues editaremos de forma definitiva /etc/init.d/showip

root@raspberrypi:~# rvm wrapper ruby-2.0.0-p451@showip showip thin
Regenerating ruby-2.0.0-p451@showip wrappers.........
Comprobamos que se ha generado (es un enlace blando):

root@raspberrypi:~# ls /usr/local/rvm/bin/ | grep showip
showip_thin
Podemos probarlo y si hay algun fallo en el fichero de configuracion, nos lo dira:

root@raspberrypi:~# /usr/local/rvm/bin/showip_thin start -C /etc/thin/showip.yml
/usr/local/rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/psych.rb:205:in `parse': (/etc/thin/showip.yml): could not find expected ':' while scanning a simple key at line 15 column 1 (Psych::SyntaxError)

#o funcionara

Starting server on 0.0.0.0:3000 ... 

root@raspberrypi:~# /usr/local/rvm/bin/showip_thin stop  -C /etc/thin/showip.yml 
Stopping server on 0.0.0.0:3000 ... 
Sending QUIT signal to process 3001 ... 

Exiting!

Ya generado el wrapper editamos /etc/init.d/showip dejandolo como queda:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          thin
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      S 0 1 6
# Short-Description: thin initscript
# Description:       thin
### END INIT INFO

# Original author: Forrest Robertson

# Do NOT "set -e"

DAEMON=/usr/local/rvm/bin/showip_thin
SCRIPT_NAME=/etc/init.d/showip
CONFIG_PATH=/etc/thin/showip.yml
#chown=/bin/chown
#mkdir=/bin/mkdir

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

case "$1" in
  start)
        $DAEMON start -C $CONFIG_PATH
        ;;
  stop)
        $DAEMON stop -C $CONFIG_PATH
        ;;
  restart)
        $DAEMON restart -C $CONFIG_PATH
        ;;
  *)
        echo "Usage: $SCRIPT_NAME {start|stop|restart}" >&2
        exit 3
        ;;
esac

:
Los fichero creados los ponemos como propiedad del usuario deploy:

chown deploy:deploy /etc/init.d/showip
Hacemos una pruaba antes de reiniciar y ver que arranca la aplicación:

pi@raspberrypi ~ $ sudo service showip start
Starting server on 0.0.0.0:3000 ... 
Ya podemos ir desarrollando, subir al repositorio y hacer deploy con las ultimas versiones del código.

verdor@enlamina$ cap deploy
Tendríamos que dar algunos retoques si tuviéramos mas de un entrono (entorno de pruebas) y la aplicación necesitase de base de datos, etc... Enlaces:

miércoles, 16 de abril de 2014

Tips Linux

raspbian.org

Conocer el espacio en disco duro libre y ocupado:
df -h
Conocer espacio ocupado de cache apt:
du -sh /var/cache/apt/archives
Elimina del cache los paquetes .deb con versiones anteriores a los de los programas que tienes instalados:
sudo apt-get autoclean
sudo apt-get clean      #Elimina todos los paquetes del cache.
sudo apt-get autoremove #Borra los paquetes huérfanos
Ver RAM ocupada en megas y SWAP:
free -m -t
Lista de procesos que se están ejecutando:
top
Cuanto tiempo lleva arrancada su máquina:
uptime
Ejecuta un script/programa en el arranque:
sudo vi /etc/init.d/miscript        #creamos script
sudo chmod 755 /etc/init.d/miscript #le damos permisos de ejecución
sudo /etc/init.d/miscript start     #lo probamos
sudo /etc/init.d/miscript stop      #lo paramos
sudo update-rc.d miscript defaults  #lo metemos en el arranque
sudo update-rc.d -f miscript remove #cuando lo queramos eliminar del arranque
Instalar servidor escritorio remoto
sudo apt-get install xrdp
Instalar cliente escritorio remoto
sudo aptitude install remmina remmina-gnome