Ubuntu 10.04 on VirtualBoxをバックグラウンドで動かしSSH接続する

2013/01/04追記
Vagrantを使ったほうが良い

忘れそうなので、メモ。

仮想ハードディスクの入手

インストールを自分でやるのは面倒なので、仮想ハードディスクイメージのダウンロード | Ubuntu Japanese TeamからUbuntu 10.04 LTSをダウンロード。

GUIを使わない

GUIは不要なので、起動時にCUIを使うようにします。

/etc/default/grubを開いて、

GRUB_CMDLINE_LINUX_DEFALUT="quiet splash"

GRUB_CMDLINE_LINUX_DEFALUT="quiet splash text"

に変更。

再起動をするとCUIになっているかと思います。
(ただ、日本語が文字化けしてしまいます。SSHを使うので問題ありませんが。)

ホスト側からSSHで接続できるようにする

VirtualBox VMに入れたLinuxに、SSHで繋いだよ。 | Ginpen.comを参考に。
ついでに~/.ssh/authorized_keysに公開鍵を追加しておきます。

以下追記:2012/05/16 13:16

バックグラウンドでVirtualBoxを起動する

SSHで接続するので、VirtualBoxがGUIで起動している必要はありません。
資源の無駄遣いなので、headlessで動かすことにします。

$ VBoxHeadless --startvm "Ubuntu";

(”Ubuntu”の部分は仮想マシン名)
で起動できます。

オプションを忘れそうなので、.zshrcに

alias vboxstart="VBoxHeadless --vrde off --startvm "

と記述しておきました。
(”–vrde off”はVirtualBox Remote Desktop Extensionをオフにするオプション)

$ vboxstart "Ubuntu"

で起動できますね。

ちなみに仮想マシンを終了するときはSSHでログインして、シャットダウンします。

$ sudo su -
# shutdown -h 0

こんな感じですね。

Twitterに流れているNaxos Music Libraryのアルバムがみられる「twinaxos」つくりました

ご存じない方も多いかもしれませんが、月額定額制でCD50,000枚が聴き放題な、Naxos Music Libraryというサービスがあります。個人で申し込むことも可能ですし、図書館や大学などの機関が契約して使えるようにしてくれている場合もあります。

非常に曲数が多く便利なサービスなのですが、「なにか良いアルバムないかなー」といった時に適当なアルバムを見つけにくいという欠点があります。
そこで、twinaxosです。
Twitterに流れている最新100件のアルバムが表示されますので、掘り出し物を探してみてください。

twinaxos

Alfredから一発でFinderで新規ウインドウを開く方法

Mac OSXでMission Control(Spaces)を使って複数スペースを利用しているときにDockからFinderを選択すると、Finderが表示されているスペース(画面)に勝手に移動してしまいます。(Finderのウインドウがひとつもない場合は、新しいFinderのウインドウがそのスペースで開きます)

そのスペース内でFinderを開きたい場合のほうが多いと思うので、結構、不便です。

そこで、スペース移動せず、Finderの新規ウインドウを開く方法です。
色々方法があるのかもしれないですが、AppleScriptを利用することにしました。

AppleScriptを作成

アプリケーション –> ユーティリティ –> AppleScript エディタを起動します。
以下のコードを入力します。

tell application "Finder"
    make new Finder window
    set frontmost to true -- 2012/02/24 20:18追記
end tell

2012/02/24 20:18追記
Finderを最前面にするために、set frontmost to trueを追加しました。

今回はAlfredから呼べるようにしたいので、アプリケーションとして保存します。
AppleScript エディタのメニューからファイル –> 保存を選びます。

ファイルフォーマットは「アプリケーション」にして、適当な場所に保存しておきます。
(アプリケーション ディレクトリ以外に保存する場合は、Alfredの設定でSearch Scopeにディレクトリを追加しておく必要があります)

Alfredから呼ぶ

私はAlfredから呼び出していますが、Quick SilverやButlerから呼び出すこともできると思います。

djangoのテンプレートでBootstrapのNavBarみたいなやつのactive状態を操作する

親テンプレートのNavBarのactive状態をどうやって操作しようかと思い、現在のパスで判定をすることにしました。
NavBar:Bootstrap, from Twitter

コンテキストプロセッサー(context processors)

テンプレートにpath(”/music/bands/the_beatles/”のような相対パス)を渡すために、コンテキストプロセッサーを自作します。
(コンテキストプロセッサーにテンプレートに渡すコンテキストをどのように処理するかを記述する)

context_processor.pyのような名前のファイルを作成し、

def path(request):
    return {'path': request.path}

と書いて保存します。

リクエストコンテキストを生成するときに、いちいちコンテキストプロセッサーを指定しても良いのですが、今回の場合はプロジェクト全体で使用するので、settings.pyに以下を追加します

# デフォルトのコンテキストプロセッサー
TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.static",
    "django.contrib.messages.context_processors.messages"
)
# 追加するコンテキストプロセッサー
TEMPLATE_CONTEXT_PROCESSORS += (
    'project_name.context_processors.path',
)

レンダリング

以下のようにコンテキストを与えた上でレンダリングを行います。

return render_to_response('template.html',
                          {},
                          context_instance=RequestContext(request))

テンプレート

以下のようにpathを判定することでアクティブ状態を切り替えます。

<li{% if path == "/hoge/fuga/" %} class="active"{% endif %}>

本来は

{% if path == {% url someapp.views.hoge %} %}

のように書ければいいのですが、テンプレート構文がネストできないため、ベタ書きをしています。(もし出来るようでしたら、教えていただけると助かります)

RedmineをさくらのVPSにインストールする

RedmineはRubyで書かれたプロジェクト管理ソフトウェアです。
さくらのVPSにインストールしたのですが、少々困ったのでメモ。

CentOS6のインストール

まず、OSをカスタムインストールしました。さくらのVPSのデフォルトでインストールされているOSはCentOS5.5ですが、ここではCentOS6をインストールします。いつの間にか、さくらのVPSにカスタムインストール機能が実装されていたので、利用してみました。

CentOS6(32bit)を指定してカスタムインストールを実行するとVNCでリモートの画面が表示されます。あとは通常のLinuxのインストールと同じように進めていきます。CentOS6用のガイドはありませんが、CentOS5用のガイドが参考になります。

インストール後、バージョンを確認したところ、CentOS 6.2が入っていました。

$ cat /etc/redhat-release
CentOS release 6.2 (Final)

このあと、SSHの設定等を行います。

Redmineのインストール

Redmine 1.3をCentOS 6にインストールする手順 | Redmine.JP Blogに従ってインストールを進めますが、Redmineをインストールする際に注意すべき点があります。
最初、RubyForge: Redmine: ファイルリストからRedmine 1.3.1をインストールしましたが、migrationの実行時にRubyTreeがないと怒られてしまうバグがありました。

Trankから最新版(開発版)をダウンロードし、インストールをしました。
(開発版は大きなバグがある危険性があります。このリビジョンを参考に、差分を統合する方が良いかもしれません。)

$ svn checkout http://redmine.rubyforge.org/svn/trunk/

RubyForgeからダウンロードする安定版とは異なり、Railsを自分でインストールする必要があります

$ gem install Rails --no-rdoc --no-ri

Redmineの設定

Redmineを使い始めるための初期設定 | Redmine.JPを参考にしました。
非公開で運用するRedmineの場合はプロジェクトの閲覧可能範囲 | Redmine.JP Blogを参考に公開設定も変更します。

djangoのAuthenticationFormで「お使いのブラウザはクッキーを有効にしていないようです」と言われる

djangoのAuthenticationFormを使用してログイン処理を実装する際に「お使いのブラウザはクッキーを有効にしていないようです」と言われてしまう場合。
※もちろんブラウザ側のクッキーは有効にしてあります。

AuthenticationFormのclean内でrequest.session.test_cookie_worked()が呼ばれ、クッキーが有効かを判定しています。
このため、事前にビュー内でテストクッキーを設定しておく必要があります。set_test_cookie()というメソッドが提供されているのでこれを呼び出しておきます。

Django | How to use sessions | Django documentation

def login(request):
    if request.method == 'POST':
        form = AuthenticationForm(request=request, data=request.POST)
        if form.is_valid():
            login(request, form.user_cache)
            request.session.delete_test_cookie()
            return HttpResponseRedirect(reverse('someapp.views.index'))
    else:
        form = AuthenticationForm()
    
    request.session.set_test_cookie()
    return render_to_response('someapp/login.html',
                              {'form': form},
                              context_instance=RequestContext(request))

Django 1.3で静的ファイルを提供する方法(開発環境)

djangoで静的ファイルを提供する際にはまったのでメモ書きをしておきます。

djangoはウェブサーバではないため本番環境ではApacheやNginxといったサーバソフトウェアに静的ファイルの配信を任せるべきです。

djangoのドキュメントにはDjango | Managing static files | Django documentationという項があり、複数の方法が紹介されています。

今回は最初に記載されているdjango.contrib.staticfilesを使用した方法を選択しました。
Django | The staticfiles app | Django documentation

staticディレクトリを作成する

appごとにstaticファイルを分けて保存することができます。(app名)/staticというディレクトリを作成しましょう。
(デフォルトでSTATICFILES_FINDERSにdjango.contrib.staticfiles.finders.AppDirectoriesFinderが追加されているため、自動的に探索をしてくれます。)

※特定のappに関連するファイルじゃない場合はSTATICFILES_DIRSにパスを指定することで、任意のディレクトリを認識させることができます。

appはちゃんとINSTALLED_APPSに追加しておきましょう。
追加しておかないとAppDirectoriesFinderが探索をしてくれません。

テンプレート

例えば、bootstrap.cssというCSSファイルをstaticディレクトリに配置した場合、

<link rel="stylesheet" href="bootstrap.css">

のように静的ファイルのパスを指定します。

が正常に動作するために注意べきすべき点がひとつあります。
テンプレートをレンダリングする際にRequestContextを利用するということです。
Django | The Django template language: For Python programmers | Django documentation

下記コードのようにcontext_instanceを指定するのを忘れずに。

def some_view(request):
    # ...
    return render_to_response('my_template.html',
                              my_data_dictionary,
                              context_instance=RequestContext(request))

Mixi iOS SDKのコールバックでリクエストを判別する方法

バージョン:Mixi iOS SDK 1.2.1

リクエスト送信

Mixi iOS SDKではMixiクラスのsendRequest:delegate:でリクエストを送信します。このメソッドは戻り値としてNSURLConnectionを返してきます。

NSURLConnection *connection = 
  [[Mixi sharedMixi] sendRequest:request delegate:self];

しかし、デリゲートに対するコールバックではそのNSURLConnectionを利用して判別することができません。

コールバック

あまり良い方法とは言えませんが、SDKに少々手を入れます。
コールバック時にNSURLConnectionを渡すようにします。
リクエスト送信時に得られたNSURLConnectionと比較(==)することでリクエストを判別することができます。

以下の変更をSDKに加えます。MixiDelegate.hはSDK直下に、MixiURLDelegate.mはSDK内のNetworkingディレクトリに存在します。

$ diff original/MixiDelegate.h modified/MixiDelegate.h 
30c30
< - (void)mixi:(Mixi*)mixi didFinishLoading:(NSString*)data;
---
> - (void)mixi:(Mixi*)mixi didFinishLoading:(NSString*)data connection:(NSURLConnection *)connection;
38c38
< - (void)mixi:(Mixi*)mixi didSuccessWithJson:(NSDictionary*)data;
---
> - (void)mixi:(Mixi*)mixi didSuccessWithJson:(NSDictionary*)data connection:(NSURLConnection *)connection;
$ diff original/MixiURLDelegate.m modified/MixiURLDelegate.m 
52,53c52,53
<         if ([self.delegate respondsToSelector:@selector(mixi:didFinishLoading:)]) {
<             [self.delegate mixi:self.mixi didFinishLoading:@""];
---
>         if ([self.delegate respondsToSelector:@selector(mixi:didFinishLoading:connection:)]) {
>             [self.delegate mixi:self.mixi didFinishLoading:@"" connection:connection];
59,60c59,60
<     if ([self.delegate respondsToSelector:@selector(mixi:didFinishLoading:)]) {
<         [self.delegate mixi:self.mixi didFinishLoading:result];
---
>     if ([self.delegate respondsToSelector:@selector(mixi:didFinishLoading:connection:)]) {
>         [self.delegate mixi:self.mixi didFinishLoading:result connection:connection];
81,82c81,82
<             if ([self.delegate respondsToSelector:@selector(mixi:didSuccessWithJson:)]) {
<                 [self.delegate mixi:self.mixi didSuccessWithJson:json];
---
>             if ([self.delegate respondsToSelector:@selector(mixi:didSuccessWithJson:connection:)]) {
>                 [self.delegate mixi:self.mixi didSuccessWithJson:json connection:connection];

Django Authenticationのパーミッション、グループに関するメモ

Django 1.3の認証システムのパーミッション、グループに関するメモです。
Django | User authentication in Django | Django documentationから自分が気になった部分だけ適当に訳したものです。(Django Documentationのライセンスに関する表記を見つけられなかったので、もし問題がありましたらお知らせ下さい)

認証システム

認証システムには
ユーザ(User)
パーミッション(Permission)
グループ(Group)
メッセージ(Message)
があります

注:Authenticationフレームワーク内のMessage機能はDjango 1.4で廃止されます。今後はMessages Frameworkを利用してください。

ユーザ

ユーザをグループに追加

myuser.groups = [group_list]
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()

ユーザにパーミッションを割り当てる

myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

パーミッション

Djangoでは特定のユーザあるいはグループ(ユーザの集合)にパーミッションを割り当てることができます。

カスタムパーミッション

以下のようにモデルオブジェクトにパーミッションを定義することができます。

class Task(models.Model):
    ...
    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as closed"),
        )

パーミッションによってアクセス制限をかける

以下がデコレータを使用した方法です。login_urlはオプショナルな引数でデフォルトはsettings.LOGIN_URLになります。

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url='/loginpage/')
def my_view(request):
    …

さらに複雑な制限をかけるにはuser_passes_testデコレータを使うこともできます。

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/')
def my_view(request):
    ...

テンプレート内でパーミッションを扱う

テンプレート変数としてpermsが定義されます。

    <p>You don't have permission to do anything in the foo app.</p>

Mixi iOS SDKを使うアプリでURLスキームを2つ以上定義している場合の注意点

Mixi iOS SDKを使っているアプリでURLスキームを2つ以上定義している場合は、MixiクラスにURLスキームを設定しておく必要があります。

Mixi *mixi = [Mixi sharedMixi];
mixi.returnScheme = @"mixiapp-xxxx";