SharePoint Framework

去年の暮れぐらいだったか、MSのお知らせでSharePoint Frameworkという新しい開発環境を使った SharePoint SiteのCustomizationが可能になりました。という連絡があった。  自分がやりたいSPサイトのCustomizationは 基本的にJavaScriptをページに埋め込むJavaScript Injectionという手法だ。 これでクライエントサイドの描画をコントロールするCSRフックとかリストやファイルのアイテムをAjaxで読み書きするREST APIなどを使ってカスタムページを作るという方法で用が足りてしまうので、あまり気にしていなかったのだが、この方法、最近、その進化が目立つModern view  pageでは使えない。 これは開発するのにVisual Studioが必須であるSharePoint Add-Inでも同じ様で、 どうも今の時点でModern Look componentのCustomizationをサポートしているのはSharePoint Frameworkのみのようなのだ。

で、Dev.Office.comのDocumentationを眺めてみると、なんとこれ、 Node.JS上で全部動いているのだ。

NPMで yo,  gulpと @microsoft/generator-sharepoint を導入し Project folderを作って以下を実行

yo @microsoft/sharepoint

これで必要なファイル群がフォルダーにインストールされる。 hello worldのテンプレートになっているので、これでもうnode.js 上のローカルPCで動くSharePointのページを模したWorkbench上での実行が可能(下記コマンドでDefaultブラウザが勝手に立ち上がる)

gulp trust-dev-center

gulp serve

ここまで、SharePointサイトにアクセスする必要すらない。 Step by Stepはdev.office.comに詳しいので割愛 (Build your first SharePoint client-side web part (Hello World part1)

SharePointのサイトでもすでにDevelopper siteが例えば”https://mysite.com/sites/dev”などとして設定されているなら、 ”https://mysite.com/sites/dev/_layouts/workbench.aspx” にアクセスすると、開発中のwebPart のWorkbenchがSharePoint上で作動する。

そしてこのTool Chainによる開発、Visual Studioが必要ない、というか使えない。dev.office.comのお勧めEditorはVS Code. IDEの例としてJetBrainのWebStormがあげられているなどVisual Studioへの依存性が一切ない。(C#もドットnetも使わないなら当たり前というべきか)

ただ、使われているコードが通常のJavaScriptではなく、TypeScriptなのだ。 TypeScriptのコードは実行時にはJavaScriptにばらされるのでそんなに大きなLearning Curveにはならない、と予測はしているのだが、これは学習する必要があるんだろう。

Node.jsは言語というより開発環境のベースとして使われるので、これ自体を学ぶ必要はない。

VSで使っていたNugetだとかMS buildーtoolなどのツールが、下のようにNode.JS上で動くツールにおきかわっているわけで、今わかっている範囲でまとめると

  1. Node.js: Install するだけ、普通のJavaScriptの知識で十分のはず。
  2. NPM :DependencyのUpdateなど、使い方は学んだほうがよさそう。yarnでもいいのかな
  3. yo.js:Install するだけ、学習の必要性はなさそう
  4. gulp: コマンドをいくつか覚えるだけで学習の必要性はなさそう
  5. typescript: 学習の要あり
  6. webpack:@microsoft モジュールを導入したときに含まれている。さわらなくてよい。
  7. VS CodeまたはWebStorm:Dev.office.comはVS Codeを使った用例を挙げているが、自分は従来からつかっているWebStormを使う。

というわけで、なんと開発環境的には、2,3,4,5,6は1のNodeJSが動けば動くのでなんでもよく、VS codeもWebStormもマルチOS環境で動くので 要するに Linux上で開発できてしまうのだ。

というわけで、javaScriptをかじっている人間にはハードルが低そうな予感。 Linux環境でぼちぼちやってみようかな?

SharePoint Change Page Title without changing site address ページタイトルをサイトアドレスを変えずに変更する。

これってSharePointのこの部分がちゃんと動いていないだけなのではないかとおもうのだが、今現在のOffice365(SharePoint Online)のインプリメンテーションだと、Page Attributeでページタイトルを変更するとaspx ページの名前自体が変わってしまう。

たとえば https://mysite.sharepoint.com/sites/mysite/SitePages/thispage.aspx

というページがあるとして、これだと表示されるページタイトルが”thispage”となってしまう。これを Edit pageからタイトル変更して ”This Page”とすると、 サイトアドレスが

https://mysite.sharepoint.coms/sites/mysite/SitePages/This%20Page.aspx

となってしまう。サイトアドレスをなるべく短くしたいのでページタイトルとサイトアドレスの一部になるページの名前を別けることができればよいのだが、今の時点ではできない。

世の中には同じことを不便と考える人がいるわけで、何件かの記事ではSharePoint Designerを使ってマスターページを変更する方法が述べられている。すでにSharePointにある機能をターンオンするだけの簡単な修正ではあるが、

1)マスターページを変更する必要がある。
2)SharePoint Designerが必要

すなわち、サイトオーナーでかつSharePoint Designerを使えるという条件を満足していなければならない。

ブラウザーのdebug Toolで確認してみたら以外と簡単にタイトルだけ変更できることが判ったのでここに書いておく。 サイトのエディター権限があればできるというのが利点。

ターゲットのページでエディットモードに移行し、適当なところに Insert ->Embed Codeでコードエディターを開く。

以下を入力する

<script>
document.getElementById('DeltaPlaceHolderPageTitleInTitleArea').innerHTML="My Page";
</script>

これだけである。 ページタイトルが”My Page”となる。

SharePointの場合、CSRというメカニズムがあって、表示する内容の大部分は一度ブラウザーがスクリプトを実行したのち、データを描画するため、 ページへの書き込みのタイミングを遅らせなければならないのが普通だが、タイトル部分は最初の読み込み時に描かれてから変更がないため、上のようにブラウザがスクリプトを読み込んで即実行、という単純な動作でも有効なんである。

ちなみにWiki PageとWeb Part Pageの両方で有効。 Site Pageはためしていない。

 

 

constructing long string with Javascript

There is a time you need to construct a string (for instance, to create a html block) in your code.

In the simpliest approach, youcan constract the string variable  like so

var html='<head><body>’+contentVariable+’more stuff’ + ‘</body></head>’;

this becomes very messy quickly once more variables, more nested construction is needed.

I used to keep concatinating the string, like so

var html='<head></body>’;

html +=  contentVariable;

html += ‘ more Stuff’;

html += ‘</body></head>’;

 

 

Then I saw a pattern in the couple of codes from internet;

var h=[‘<head><body’];

h.push(contentVariable);

h.push(‘more Stuff’);

h.push(‘</head></body>’);

var html=h.join(”);

The More concatenation needed, the more convinient the last method becomes. Key is to join the array element with null delimiter.

exploring SharePoint Online

Our office is soon moving to SharePoint online. Currently we are using SP2007 and Microsoft does not support content migration from 2007 to 2013 or SP online. This is good and bad. Good because we can build sites from scratch, bad because there is no easy way to move our contents from SP2007 to SP online. We should be able to copy files and folders from 2007 to online but all the metadata will be lost. lists will be even tougher. we have the third party solution called ShareGate but IT guys are telling us it is faily slow we can not possibly migrate the whole sites (that is in the size of the order of Terabytes.) and would like to selectively use the tool. Document Management is tricky under the SharePoint at best.

UI has been greatly improved. It is now much easier to interact with contents with JavaScript. I am having tremendous fun with technique like CSR (client side rendering) and REST API that can be used with CSR or as a conetnt of CEWP as usual.  Furthermore , attaching JavaScript code to web part is made less painful by the introduction of JsLink option and inclusion of script web part.

It is also good to have started late in the game. Internet is filled with power user tips. (I can use most of the technique meant for SharePoint 2013 with SharePoint online.)

One of my favorite technique called “calculated column” is still possible with much less hassle.  Again CSR can be used for this with literally one line of code.  Even better, I can forego with calculated columns at all and directly manipulate the target columns and show bar graph or traffic signal instead, using CSR’s context override.

Filter/connection of WebParts on the page is now performed on the list and not view. In another word, the filtering column do not need to be a part of the view.  This is tremendous for me. I no longer need to hide a column that is used for my filter because I don’t need to include the column in the view to start with.

EasyTabs that we used and found so useful for SharePoint 2007 does not work as is.  Again somebody has modified it for SharePoint 2013 and it is  working. Christophe seems to have developed another tool package that includes EasyTabs functionality but my inquiry to him went unanswered so I am using this version.

There is another code called Hillibily Tabs which essentially do the same thing as EasyTabs.  This one uses jQuery and jQuery UI (and CSS) to manipulate the tab, so how do I say this..  It’s flashy and probably more maintainable.

Excellent write up on CSR by Andrei Markeev is here be sure to check other articles by him.

This one by Kaptyn is also good

Many CSR examples are on Office Dev Center, uploaded by Muawiyah Shannak.

The above examples contains calculated column like effect witihout using the calculated column.    However, if you insist Calculated columns to be used, here is Christoph’s explanation of how it can be done.

List Roll up

I was first thinking maybe we need to purchase third party package to do this.  It turned out this is doable with home made JavaScript code with REST API. I am able to Roll up the list (read only at this time, because I only feel comfortable with “GET” potion of the API) in my sandbox, using a couple of sub-sites.  I will try and see how scalable this technique is.

Minimum Download Strategy

Sooner or later, people will hit this “MDS” *issues*  where the view changes back to its default look when switching the view,  or code breaks because it can not find jQuery that was supposed to have been loaded.  I am still learning this but found some blog entries very helpful.

  1. Article by Kalmstrom.com talks about what happens with MDS in very short text and also give pointers to how to deal with it
  2. SharePoint 2013 – A Better Pattern for Client Side Rendering Scripts shows a script pattern that can be used for site with or without MDS feature enabled.

However, my observation is that once you introduce your own code to the mix, then SharePoint engine with MDS seems to try render first with MDS way, then try to render again for “foreign” code.  Because of this, some of the pages does load faster with MDS off.  So turning this feature is not as bad as it may sound.

 

Most of the link here are from various blog entries.  Again, it must be much easier now than two years ago to find the information I need.  MSDN also have many documents I can refer to but there coverage is broader (C#, XML ,.aspx and JavaScript code).  As a business side power user, I (can) only use JavaScript and find those individuals’ entries priceless. My appreciation goes to those who spent many nights to figure out and then took a time to write about it!

SharePoint online :: modifying “New item or Edit this list” to “Edit this list”

This is my first “SharePoint Online” related javaScript.(I am still experimenting with nuance of SP online)
This script changes “New item or Edit this list” links to simpler “Edit this list link.


/**
* Created by A2life on 3/24/2016.
* Modify new or edit div to "edit this list" only
* modify "New items or edit" elements on entire page (not just webPart this is attached to)
* */
(function () {

var thisContext = {};
thisContext.OnPostRender = modifynewEdit;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(thisContext);

})();

function modifynewEdit() {
// jQuery library is required in this sample
// Fallback to loading jQuery from a CDN path if the local is unavailable
(window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.11.3.min.js"><\/script>'));

jQuery("td.ms-list-addnew:contains('new')").each(function (index) { //only respond to "New" elements
var edit = $(this).find('a:contains("dit")'); // because I am looking for "[E|e]dit"
edit = edit.text("Edit").add("<span> this list</span>"); // reconstruct link with proper words
$(this).html(edit);
});
}

attach this to list webPart as jsLink parameter. If uploaded to Site Assets folder as “modifyEdit.js” , it should look like “~site/SiteAssets/modifyEdit.js” . “~site” is a token for the site that sharePoint uses to resolve the url reference.

Note on this code.

  • The document.write line dynamically writes a script tag for jQuery. This appears to be more reliable way of loading jQuery rather than referencing to the file within script tag.
  • The code creates a context override for onPostRender SP event for the webPart (of item list view) being attached. This event seems to fire even when other list view on the same view is changed  (and the code invoked will affect other list views on the same page as expected) so the function modifynewEdit is attached to this event.

Hiding SharePoint list column from list view

This article is about a javascript snippet that hides a specific column from a SharePoint list view. If I google this subject, most of the articles found on the Internet is about hiding a specific column from new, display or edit form. Although javascript can do this, you can do the same thing without use of javascript by enabling list content-type as well. See here.

Not many articles talks about hiding columns from the list view though. (This one is an exception)
The link above shows the solution for toggling the particular columns. I only needed to hide a column from the list. But why do I even want to do that when one can simply create a view without that specific column you don’t want to see?
The reason is that I want to show the list based on filtered value from the column in question. I can add the filter webpart that I can connect to the target list, then specify the column to which the filter webpart will be connected to. In another word, for the filter to work, the column need to be a part of the list view (This is no longer the case with SharePoint 2013 or SharePoint online.  See below). Since the column will always show the same value for all displayed items(filtered value) I want to hide this column. If your company allows the use of SharePoint Designer, then you can use the Dataview webpart where you can use the column that is not shown to filter the items list. But Dataview creation and editing requires SPD. I wanted a easier solution, hence this javascript snippet.

if (typeof jQuery === 'undefined') { throw new Error('hide column snippet requires jQuery') }

//This function gets targetTable object and columnindex to hide
//targetTable is a jQuery object with single element.
function doHideColumn(targetTable,col) {
    targetTable.find(".ms-viewheadertr >*[class^='ms-v']").eq(col).hide();
    targetTable.find(" >tbody >tr").each(function(){$(this).find(">td:eq("+col+")").hide();});
}
$(function() {//this hide the colName column from all table in the page
    var    colName="colToHide";
    var    tarray=$("tr.ms-viewheadertr th:contains('"+ colName +"')");
    var    tlength=tarray.length;
    var    colindex;
    for (var i=0; i<tlength; i++) {
        colindex=$(tarray[i])[0].cellIndex;
        doHideColumn($(tarray[i]).closest('.ms-listviewtable'), colindex);
    }
});

 


This code snippet requires jQuery. You can use content editor Web Parts (CEWP) to include this code (don’t forget to wrap the code with script tag.) It works with SP2007 (My office’s current version) I may need to look at the code again when our IT upgrades the server to either 2013 or O365.  *Edit*  On SharePoint 2013 and SharePoint online filter can be applied to any list column regardless of if the target liist view contains the filtered column.  Therefore, solution explained here is unnecessary. *end Edit *
The code above scans the entire page for column headers with “colToHide” name and hide the column. (or columns if there are multiple lists in the page and if they contains the column with same name)
Since this code uses jQuery array object to hold the column information, it wont be difficult to modify the code to accept more than one column names to hide multiple columns from single list. For now, this snippet achieves what I need.

Filter Web parts are nice. For instance, URL query web parts let me create a page that contents are based on the filtered value in url query. For instance,
http://projectpage.aspx?projphase=1
http://projectpage.aspx?projphase=3
both link goes to the same page but the first link will show project phase 1 list items where the next link will show project phase 3 list.

Raspberry Pi でパソコン電源をInternet上から操作

家の外部からタブレットなりノートパソコンなりを使って自宅のパソコンにリモートアクセスするためのアプリというのは色々ある。Internet経由でアクセスする、というもので、Linuxでは当たり前のように実装されているし、 WindowsでもRemote Desktopというアプリケーションが同梱されているし、ファイアウオールでRemote Desktopが使えない環境でもWebベースのTeamViewer とかlogmeinというサードパーティの製品を使えばセキュアな接続がいとも簡単にできてしまう。 Chromeをブラウザとして使用しているのならChrome remote desktopというアプリが今の旬である。

 なぜそんなことが必要か、という疑問が湧くかもしれないが自分の場合、外部からお気に入りの開発環境にログインし、コード開発を一つのマシン上で行う、という使い方がメインになっている。 もちろん将来的にすべての作業がブラウザ上でできる、という環境が構築されればそんな必要はなくなるわけだが、

問題はパソコンにアクセスするには当然のことながら当該パソコンの電源が入っていなくてはならない、という事。
 エコの観点からみると年がら年中つけっぱなしになっているパソコン、というのはエネルギーの浪費に見える。 WEBサーバーを自宅のパソコンを使って構成していた時には電源をつけっぱなしにするしかなかったのだが、アイドル状態でも常に80Wくらいの消費電力が発生していた。
 現在はCubieboardという、手のひらに収まるサイズのArmcortexの開発ボードをサーバーとして使って賄っており、消費電力は3W以下だ。

で、パソコンの電源を使うときだけ遠隔操作でオンする方法がないか調べてみた。

 InstructableにElectric Impというモジュールを使って電源のオンオフをする方法が紹介されている
このモジュール、SDカードと同じform factorだが、内部にWifiモジュールとArm Coretex M3を内臓したれっきとした開発ボードであって、クラウドサービスに接続してパソコンやタブレット上から専用のコントロールパネルアプリを使って接続されたデバイスのリモートコントロールができるようになっている。

InstructableではこのElectric Impに簡単なトランジスタを追加して、PCのPower switch lineを瞬間的にショート状態にする。(つまりパソコンのスイッチを押したのと同じ状態にする)ことによってPCを起動する方法が述べられている。 Electric Impの値段は25ドル程度だが、サポート用の部品(Imp用のブレークアウトなど)を買い足すと40ドルくらいの出費になりそうだ。
自宅でcubieboardのWEBサーバーを随時動かしているのであえてアカウントを作ってクラウドを使ってコントロールする必要はないわけで、 そうすると似たようなことはArduinoでもできるはずと思うわけだが、これまたArduino本体にWifi、あるいはEthernetシールドを追加すると40ドルくらいの出費になる。 CubieBoardのGPIOをパソコンのスイッチに接続して操作することも可能だろうが、部屋が2階と地下室に分かれているし、メインサーバーになっているカードのGPIOで他のデバイスをハードウエアコントロールというのは安全性の面から心理的抵抗がある。

そこで遊び終わって引出しに眠っていたRaspberry Piを使うことにした。Desktop用のLinuxが走るほどのグラフィック性能を持つボードをただの電源スイッチとして使う、というといかにももったいない感じがするのではあるが Piの値段も含めて40ドルくらいで済んでしまうのでコストパーフォマンスの面から考えると他の方法に比べても高くはない、というか他の手間を考えるとこちらのほうが安上がりの感じ。

調べてみるとデバイス制御をPythonベースのhttp サーバーから実行できるWEBIOPIというPi用のライブラリーを発見した。 これをインストールするとGETとかPOSTのHTTP用のプロトコルを使ったRESTという手法でハードウエアのコントロールができるようになる。 つまりWEBサーバー上にページを作り、そのページ上にボタンを描画して、WEBIOPIで提供されているRESTコールを紐つけるという方法でPiのGPIOピンの遠隔操作ができるようになる。 このRESTという手法、非常に単純で、urlのパスに模してパラメーターをサーバーに送ってあげるというもの。GETはアドレスをブラウザで指定するだけで実行できるのでたとえば APIですべてのGPIOの状況を取得するAPIを使うには webiopiをバックグラウンドで走らせている状態で、

https://example.com/GPIO/*

とアドレスをブラウザに打ち込むだけで、Jason書式でGPIOの各ピンの状況が返ってくる。 ただし、これではページの表示自体がJasonのレスポンスになるので実用的ではなく、実際にはJavaScriptでコードを書くことになるが、webiopiにはうwebiopi.jsというヘルパーファイルが同梱されているので、使う難易度は低くなっている。

GPIOの使い方だが、
出力用に設定したGPIOピンをトランジスタを介してパソコンの電源スイッチとパラレルに接続し、パルス上の信号を出力してやるとパワースイッチを押したのと同様のことになり電源が立ち上がる。(電源が入っているときには逆に電源が落ちる)。電源スイッチへ接続されるピンはパソコンのマザーボード上のフロントパネルコネクター部分(パソコンケースのケーブル類を接続するコネクタ部分)に接続ピンがあるのでワイヤーをスプライスしてつなげてやればよい。。
また信号を出す前にパソコンの電源が入っているかどうかをわかっている必要があるのだが、フロントパネルコネクターには電源表示用のLEDへ接続されるピンも存在している。 そこでこのピンをGPIOでモニターすることによってパソコンに電源が入っているかどうかの判定をすることにした。

実際に組んだ回路。使ったGPIOピンは25をパワースイッチ用の出力に、24をLED電圧モニター用の入力にそれぞれ使用。 IntelのPC Interface 仕様(下に抜粋を載せます)を読む限り、パワースイッチ端子はトランジスタに直接接続(PWR+をコレクタ側に、PWR-をEmitter側に)しても大丈夫と思うが、5Vの小型リレーがたまたま手元にあったので使ってみた。NPNトランジスタのかわりに2N7000のようなFETを使えば、R1は必要ない。入力ピンのほうはLEDのVfでクランプされる電圧になるので規定の3.3V以下。万が一LEDがオープンとなっ場合5Vかかってしまうが、GPIOには保護用のクランプダイオードくらいはいっているのだろうと勝手に思い込んでいるので,保険は電流制限のR2のみ。

Table 5. Switch/LED Front Panel Electrical Connection

Pin Signal Description
2 FP PWR/SLP MSG LED pull-up (330 ohm) to +5 V
6 PWR_SW_P Power Switch high reference pull-up (10000 ohm) to +5 V
8 PWR_SW_N Power Switch Low reference pull-down (100 ohm) to GND

贅沢の極み?

贅沢の極み?


html pageの記述


<!DOCTYPE html>
<html lang="en">
<head>
<base href="https://example.com/" />
<title>PC power </title>
<!--[if IE]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
</head>

<body>
    <h2>Turn On Basement PC</h2>
    
パソコンの電源操作ボタンでやんす。!
<form class="buttonBar"></form>

<script type="text/javascript" src="//code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="poweronbutton.js"></script>
</body>
</html>

参照されているJavascriptの記述

/**
 * Created on 5/4/14.
 * poweronbutton.js となっているが、実際にはGPIOのモニターも行う総括的なコード
 * powerbutton element id='pb'
 * html form tag class = buttonBar.
 * GPIO #25 connected to 1n2222 which drives spdp relay to momentariry close power switch.
 * PC power switch is momentary switch.  if PC is off, it will turn on PC.  if PC is on, it will turn off pc
 * relay connected to power connections of PC system panel terminals.
 * GPIO24 connected to Power LED terminal.
 * webiopi (python httms and coap server) installed on target raspberry pi
 *
 */
function setupGPIO(){   // set GPIO25 to out for pc power switch connection.
                        // and  GPIO24 to in  for monitoring PC power LED terminal status
    $.post( 'https://example.com/GPIO/24/function/in',
        function(data) {
            if (data==='IN')setTimeout(monitorPower(),1000);
                  });
    $.post( 'https://example.com/GPIO/25/function/out',
        function(data) {
            data =(data=='OUT')?'PC Power':'setup failed';
            $('#pb').attr("value",data);

        });
}

// }
function turnon(){ // RET command to output pulse
    $.post(
        'https://example.com/GPIO/25/sequence/1000,010',
        function(data) {
            data=(data==0)?'Power switch pushed':'NG';
            $('#pb').attr("value",data); }

    );
}
function monitorPower(){//monitor GPIO 24 status every one second
    $.get('https://example.com/GPIO/24/value',
        function(data){
            data= (data==='0')?'PC is OFF':'PC is ON';
            $('#powerstatus').html(data);
    setTimeout(monitorPower(),1000); //call myself every 1second

})

}
$(function(){
    $('<input type="button" class="power" id="pb" />')
        .appendTo('.buttonBar')
        .attr("value", "Initializing")
        .attr("title", "Turn on Somethin'")
        .click(function () {
            turnon();
        });
    $('<div></div>')
        .appendTo('.buttonBar')
        .attr('id','powerstatus');
      setupGPIO();
    }
);

ターゲットのRaspberry Piにwebiopiが導入され起動されていることが前提になる。 また、上の方法では同梱されてくるwebiopi.jsは使わずに自前のJavaScriptでREST APIを直接アクセスしている。

ページの仕組み:
ブラウザーがページを読み込み終わった時点で、上のjavascriptが以下の作業を実行する。
ボタンを描画し、ボタンのラベルを”Initializing” と表示する。
GPIO25を出力ピンに設定。 ボタンのラベルを”PC Power”と書き換え、ボタンのクリック動作にパルスを送信するRESTコマンドを紐つける。
GPIO24を入力ピンに設定。同時に入力ピンの1秒ごとのモニターをスタート。WEBIOPIからRESTで返された状況に応じてページ上に”Power is ON” または ”Power is OFF”を一秒ごとに更新表示

JavaScriptの部分はRefactoringやnamespacing をやっていないので改善の余地あり。またPower LEDのモニターだけではパソコンがオンしていることはわかっても、実際にWindowsが立ち上がっているかどうかはわからないので、何らかのインターネットサービスをPi側からモニターする手法を併用するほうがよさそうだし、CSSの記述も追加してページの見栄えもよくしたいと思うが、一応初期の目的はこれにて達成。

なお、WEBIOPI自体にログイン形式のセキュリティ機能が実装されており、ページの最初のロード時にログインネームとパスワードを聞いてくる仕組みになっている。ログインとパスワードの初期値がそれぞれ”webiopi” と”raspberry” となっているので、マニュアルの手順に従って変更しておく必要がある。

また、Raspberry Piへの電源だが、パソコンの電源に5V standbyが存在しているため、ここから引き込んでいる。24p/20pコネクタの紫の線だが、マザーボードの電源側への要求スペックが500mAで電源側の仕様が2Aなので余裕のようだ。Raspberry PiもPCの筐体に入れてしまったので見た目もすっきりである。

<後記> 電力消費計を入手したので、実際のところ、どれだけエコになっているのか測定してみた。 パソコンを普通に電源投入すると80Wくらの消費になっていた。 パソコンをオフにすると7Wだ。パソコン用の電源が動いていて5Vのスタンバイ電源からPiとその他に供給しているということだ。 その差73Wだが、電気代で考えるとまったくパソコンをオンしなかった場合、年間約50ドルちょっとの節約になる。パソコンの稼働率が10パーセントくらいと仮定すると45ドルの節約なので1年でもとが取れる計算になる。

困ったときはログファイル

Cubieboard2 (Arm7 Cortex Dual core 1GHz, 1GByte Ram, 4GByte Flash, OS=armhf debian 7) という、約60ドルで中国から購入したデベロッパーボードを使って運営しているホームサーバーの管理にISPConfig3という管理ソフトを導入して使用している。 Mailサーバー、Webサーバー、DNSそしてnginxプロキシなどをWEBブラウザから一括管理できるので重宝している。
このツール、HowtoForgeというサイトでサポートされていて、”Perfect Server” というシリーズで多様な組み合わせのサーバー設定のチュートリアルが掲載されている。 たとえばこの記事はOSはDebian,サーバープロキシにnginx, mailにはDoveCot、DNSにはBindを使ったサーバー構築の手順が述べられており、実は自分のサーバーはこれを参考にして立ち上げた。(DNSとNGINX、PHP、MySQLの部分はともかく、メールサーバーとメールフィルターの設定は自分ひとりの能力では手も足も出なかった。きちんと設定できたのは上の記事のおかげである)
 最近バージョンのアップデートをしようと思い立ち、コントロールパネルに指示されているiSPsonfig-update.shというコマンドを実行してみた。  アップデート自体はまったく問題なく行えたのだが、 コントロールパネルにログインしようとしてみたところいつもログイン画面が出るはずのurlが空っぽのページになっている。 
他のサービス(メール、Webサイト、DNS、SSHなど)は普通に動いているので、IPSConfigのダッシュボードへのログインが表示できないという限定された不具合だ。 幸いなことにISPConfigのUpdateツールがまず実行するのは旧バージョンのバックアップなので最悪の場合はリストアを行えばよいが、ページのヘッダー情報を見てみると、エラー番号が500、Internal Server Errorとなっているので、これはPHPの実行時、ページレンダリングの途中でおかしくなっている、とあたりをつけた。 NginxのErrorLogを眺めてみると大当たり、Fatal Errorが記録されていた。

11:54:25 [error] 3452#0: *528 FastCGI sent in stderr: "PHP message: PHP Warning:  require_once(/usr/local/ispconfig/interface/lib/config.inc.php): failed to open stream: Permission denied in /usr/local/ispconfig/interface/web/index.php on line 31
PHP message: PHP Fatal error:  require_once(): Failed opening required '../lib/config.inc.php' (include_path='.:/usr/share/php:/usr/share/pear') in /usr/local/ispconfig/interface/web/index.php on line 31" while reading response header from upstream,云々

上のエラーメッセージはindex.phpの31行目config.inc.phpを読み込もうとしたところ、拒否されました。と言っている。 ../libr/config.inc.phpのアクセスレベルがきつすぎるようだ、。
そこでこのファイルを調べてみるとOwner,GroupともISPCONFIGとなっているのは良いとして、Ownerのみに読み書き権限があたえられており、Groupレベルで読み書き禁止となっている。  それではと、Groupレベルでの読み出しも許可に書き換えてみたところ、あっさりと復活した。

#  chmod g+r config.inc.php

これが普通とは思わない。何らかの理由でサーバーのワーカープロセスとファイルのオーナー情報が背反しているためにファイルアクセスできなくなっていると考える。 少し思い当たることがあって、同じサーバー内部でModxを使ったサイトを運営しているのだが、アップデートするたびにSetupフォルダーをマニュアルで削除しなくてはならない、という作業が発生している。 Setupフォルダーの削除はインストール画面でチェックをいれてやれば自動的に行ってくれるはずなのだが、このサーバーではそれができてない。

というわけで、本日わかったこと。
1. Linuxのアクセスレベル管理がいまいち理解できてないなあ。
2. Linux 不具合解析はまずError Logを読む事。

nginx でmodx のFriendly URL をrewrite

まだ十分理解できているわけではないので、最適解かといわれると疑問がのこるが、とりあえずは動いているということで、

server {
server_name cubie2.example.com;
access_log /srv/www/site1/logs/access.log;
error_log /srv/www/site1/logs/error.log;
root /srv/www/site1/public;
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args @modx;
}
location @modx {
rewrite ^/(.*)$ /index.php?q=$1&$args;
}
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
.
.
.

}

リライトには3回パスをとおしている、ということかな?

NGINX ん、じんくす? 違わい、エンジンXだい!

nginxと書いてエンジンエックスと読むそうである。webサーバーとして動くことは勿論だが、その他, リバースプロキシとしてはWEBのみならず、mailも扱えるということなので、 今回raspberry piにインストールしてみた。 徐々に使い方を覚えていき、他のサーバーからの移行を画策していこうと思う(狙いは省電力化)が、とりあえずはPHPおよびmysql を一緒に実装し Lamp ではなく、LNMPとして動かすことをやってみる。 Wikipediaの解説によれば非同期のイベント駆動モデルを使っており、プロセス・スレッド駆動のapacheなどのサーバーに比べると高負荷になっても動きが鈍くならない、という利点があるらしい。なんとなくraspberry pi にぴったりのサーバーのような気がしてきたが、実際は如何に。

実装後のテスト画面は以下。ごらんのとおり、PHPが実装でき、phpmyadminが動いている、という証拠スナップ。

phpinfo()をRPi上で実行。

phpinfo()をRPi上で実行。クリックすると拡大画面になり、raspberry piのバージョン情報などが見える。

以下のconfig file を参照。

以下のconfig file を参照。

いくつかネット上の記事を参照したが、メインはこちらの記述に従った。 上記サイトのコピー記述になるのでどうかとも思うが、とりあえず実行したコマンドだけ羅列すると以下になる。
なお、ヘッドレスでアクセスをしているので、入力はすべてsshによるリモートターミナル経由だ。

mysql-server をまずインストール

sudo apg-get install mysql-server [Enter]

mysql のルートパスワードを要求されるので入力したパスワードは忘れないようにしよう。

次にnginx本体をインストール。 ところで、サイトによっては、「ディストロについてくるnginxは0.6とえらく古いのでソースを落としてきてコンパイルしよう、」とその方法を詳しく説明してるところがあったが、apt-get update; apt-get upgrade 後にインストールしたバージョンは1.2.1であった。 ソースをみるとすでに1.51がリリースされているが、ものすごく古い、というわけでもなかったので、パッケージ品をそのまま使うことにする。 自分も齢60歳。いちいち凝っている時間はもうないので次に次にと進むのである。

sudo apt-get install nginx [Enter]
sudo service nginx start [Enter]
sudo apt-get install php5-fpm [Enter]
sudo apt-get install php5-imagick [Enter]
sudo apt-get install php5-curl [Enter]
sudo nano /etc/php5/fpm/php.ini [Enter]

最後のコマンドではnano editor が起動するので、Ctl-W で、以下の部分を探し、修正。
“upload_max_filesize=2M” => “upload_max_filesize=10M”
Dynamic Extentions のセクションに 以下を追加

extension = imagick.so

あとはCtrl-O でセーブし、Ctrl-x で終了。

phpmyadminをインストール

sudo apt-get install phpmyadmin [Enter]

Web-server selection の画面でApache か lighttpdかどちらのサーバーかと、と聞いてくるが、どちらでもないので、チェックを外しておく。 次の画面でパスワードを設定。

sudo service php5-fpm restart

以上すべてsudo で暫定ルート権限で実行しているが、面倒であれば、sudo su でルートになれば、sudoは省ける。

ここまでで必要なサービス(nginx,mysql,PHP5)はすべて導入された。 ちなみにこの状態でRPiのIPアドレスをブラウザで見ると”Welcome to NGinx”という簡単なメッセージが出て、nginxが無事動いているということがわかる。

ただし、この状態では静的なファイルしか表示しない。 PHPファイルを認識させるにはconfig file をいじる必要があるが、その前にサイト用のダイレクトリを設定しておく。
ルートフォルダにある/srvにフォルダーツリーを作っていく.

sudo mkdir /srv/www [Enter]
sudo chown -R USER1:www-data /srv/www [Enter]
sudo chmod -R 755 /srv/www [Enter]
mkdir /srv/www/site1 [Enter]
cd /srv/www/site1 [Enter]
mkdir logs [Enter]
nano logs/access.log (ファイルを作るだけなので、カラのファイルをセーブして即クローズ)
nano logs/error.log (ファイルを作るだけなので、カラのファイルをセーブして即クローズ)

上でやっているのは、nano で空のファイルを二つ作るということだが、空のファイルを作る技としてはほかに

touch filename

さらには

> filename

なんてのもある。最後のコマンドは無入力をfilenameにリダイレクトする、という技で、20年前に感心して覚えたのをすっかり忘れてた(爆)


mkdir public [Enter]

上の例では自分はUSER1というユーザー名でログインしてると仮定し, /srv/www/というフォルダーにsite1というフォルダーを作成する。 srv/www/site1/pulicを、作ろうとしているサイトのルートとしてここにWeb 構造を展開して使う魂胆である。ホストできるサイトは一つだけではないので、その場合はsite2, site3など、任意名のフォルダーを作って割り当てていけばよい。
次にCONFIG FILE で上の情報をつなぎ合わせるわけだ.
デフォルトのCONFIG FILE は /etc/nginx/nginx.conf というファイルで、これはすでに存在している。 ネット上の多くの説明では、このファイルを直接いじるような印象だが、 今回インストールされたnginx.conf を見てみると、ほとんどコメントアウトされていてコメントを抜くと、フレームワークがあるだけで、ほとんど何も実際のコマンドになっていない。 ただ、webサーバーを指定しているhttpブロックをよく見てみると 以下の記述があることに気付く。

include /etc/nginx/sites-enabled/

で、このsites-enabled のフォルダーを眺めてみると、default というファイルを見つけたわけだが、このファイルは実体のないソフトリンクされているポインタであり、実際のファイルは/etc/nginx/sites-available/default というファイルだったりする。

このsites-available, sites-enabled というフォルダーはapache2 でもおなじみで、サイトの構成ファイルをsites-available のほうに、one site= one file 単位でセーブしておき、 有効にしたいサイトのみ、ソフトリンクでsites-enabledにソフトリンクする、という仕組みになっているようだ。 ”welcome to nginx”というメッセージはこのdefault の中に以下の記述がある。

root /usr/share/nginx/www;
index index.html index.htm;

これは「このサイトのルートページはローカルマシンの/usr/share/nginx/www フォルダーですよ、html とhtmのエクステンションを探して表示しましょうね、」と言っている。 ちなみに、このフォルダーをみてみると、index.htmlというファイルがおいてあるので、その中身をみると、やはり”welcom to nginx”とhtml で書いてあるわけだ。
今回は/srv/www/site1/public/をルートにしようとおもっているので、別のconfig ファイルをつくり、そのファイルをsites-availableにセーブし、ソフトリンクでsites-enableに登録するという作業を行う。 ファイルの名前をsite1として話を進める。

sudo nano /etc/nginx/sites-available/site1 [Enter]

実際のファイルの中身は以下のようになる。

server {
access_log /srv/www/site1/logs/access.log;
error_log /srv/www/site1/logs/error.log;
root /srv/www/site1/public/;
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /srv/www/site1/public$fastcgi_script_name;
}
location /phpmyadmin {
root /usr/share/;
index index.php index.html index.htm;
location ~ ^/phpmyadmin/(.+\.php)$ {
try_files $uri =404;
root /usr/share/;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
location ~* ^/phpmyadmin/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ {
root /usr/share/;
}
}
location /phpMyAdmin {
rewrite ^/* /phpmyadmin last;
}
}

このファイルをソフトリンクするついでにdefaultをsites-enabled から削除(リンクを解除) さらにサービスを再スタート

sudo ln -s /etc/nginx/sites-available/site1 /etc/nginx/sites-enabled/site1
sudo rm /etc/nginx/sites-enabled/default
sudo nginx restart

まだルートフォルダにはページをつくっていないので、このままでは何も表示しない。 phpinfo() というphp関数を実行するだけのファイルを作成してルートフォルダーにセーブする。

nano /srv/www/site1/public/index.php

以下の一行を記述

<php? phpinfo(); ?>

ctl-o で書き込み、ctl-x でクローズ

キーボード、モニター付きのRPiなら、あとは”localhost”とブラウザに打ち込むわけだが、外部のマシンからのブラウザアクセスをする場合にはIPアドレスを入力してやる必要がある。自分の環境ではローカルマシンでbind9というDNSをうごかしている。ここに192.168.1.97というローカル固定IPをraspberrypi.home.lanというドメインネームとして登録した。早速これを使って http://raspberrypi.home.lanと入力すると一番上の画面が出てきた。 さらに http://raspberrypi.homel.lan/phpmyadmin と入力してphpMyadminのログイン画面が出た。 このアプリはPHPで動くので、PHPの作動確認OK. さらに ログインしてmysql のデータベースもちゃんと使えることを確認して本日のところは終了。 config の部分についてはnginx.org/document/ のビギナーズガイドが非常に参考になった。
外部からのアクセスができるようにするにはserver_name などのパラメータを追加していく必要があるはずなので、今後ぼちぼち試行錯誤していこうと思う。理屈としてはこれでWordPress などのCMSも導入可能になったはずだ。