背景

  • 本来のドキュメントは https://mastodonpy.readthedocs.io/en/latest/index.html
  • なんだけども、読んでも返り値とかはわかるけどもなんか書き方が感覚と違う
  • なので、自分が使う分だけメモすることにした
  • 認証不要で取得可能なものは、自分で直接 HTTP リクエストを投げたほうが楽な気がする

使い方

pip install mastodon でインストール可能。

初期化

以下の感じで初期化する。

この例は、Mastodon の Web から設定 → 開発を使って自分でクライアントを登録している場合の例。そうでないなら、クライアントの登録とアクセストークンの取得を行う必要がある。

1
2
3
4
5
6
7
8
`from mastodon import Mastodon

mastodon = Mastodon(
access_token = 'アクセストークン',
client_id = 'クライアントキー',
client_secret = 'クライアントシークレット',
api_base_url = 'URL。例えば https://mstdn.jp'
)

アクセストークンに紐づくアカウント情報の取得

account = mastodon.account_verify_credentials()

返り値は https://mastodonpy.readthedocs.io/en/latest/index.html#user-dicts

自分のアカウントのトゥートを取得

toots = mastodon.account_statuses(account)

account は、前述の mastodon.account_verify_credentials() の返り値でも良いし、アカウント ID(数字)でも良い。自動的に適切なものが使用される。

なお、返り値は 20 件。

一度取得したトゥートの続き、前、残り全部を取得する

取得したトゥートの dict をそのまま渡せば自動的に続きを取得できる。

1
2
3
4
5
6
`next_toots = mastodon.fetch_next(toots)
prev_toots = mastodon.fetch_previous(toots)

# 残り全部を取得する。ただしリクエストをループするので負荷注意。
# また、API リクエスト回数リミットも注意
remain_toots = mastodon.fetch_remaining(toots)

トゥートの削除

mastodon.status_delete(status_id)

負荷注意。Mastodon において削除処理は意外と負荷が高いです。

ほんとにメモ

  • Raspberry Pi OS (aka Raspbian) 32bit

インストールしたソフトウェア

zabbix

  • 5.0 LTS
  • 公式にあるとおり、apt リポジトリ追加してインストール
  • PostgreSQL

Java

  • Jenkins ノードになるため必要
  • apt install java8-jdk-headless

beep

https://github.com/yakumo-saki/raspberrypi-beep/

  • apt install wiringpi
  • apt install python3-pip

NodeRED

https://nodered.org/docs/getting-started/raspberrypi

  • スクリプトを使ってインストールした。node.js も同時にインストールされる。
  • NodeRED 内から、node-red-contrib-aws 追加

  • 2019/10/10 初版
  • 2022/05/02 この手順で問題ないことを確認しました。あと少々追記

前提

  • 2019/10/10 現在の方法です。
  • Object Storage は Free Tier が 20GB あります。

参照 Qiita

https://qiita.com/kaohas/items/898efe9e5aa35f2a1402

ですが、現時点では少々手順が変わっているのでメモ

バケットの作成

バケットの作成自体は特におもしろい事はないので省略しますが、参考記事には
「バケットをルートコンパートメントに作成すること」 と書かれているのでその通りにしました。
バケット一覧の画面で(ルート)と書かれていれば問題ないでしょう。

2022/05/02 追記 ルートコンパートメントである必要はありません。少なくともコンパートメントを移動しても問題ありませんでした。

アクセスキーの作成

ここが参照 Qiita と異なっているので、メモしたかった所です。
2022/05/02 追記。テストであればこの手順でも良いと思いますが、本番等であれば次の項目の手順を行ったほうがよいと思います。

テスト用手順(管理者ユーザーの権限でアクセス)

  • アイデンティティ → ユーザー から自分のユーザーを選ぶ。 メールアドレスが ID になっているものを選択しました。
  • 左下のリソース欄にある 顧客秘密キー をクリックします。
  • 秘密キーを生成 ボタンをクリック
  • 名前は何でも良いので自由に付ける。

真ん中に表示されたキーは、再表示できないのでコピーして保存しておく。

アクセス・キー と書いてある部分(上記の図だと ..ec99be と書いてある部分) にマウスカーソルを乗せると、アクセスキーが表示される(コピーボタンもある)ので、コピーしておく。
62714b857ab1aef1df653bae5002a6bacdec99be のような感じの文字列である。

AWS_ACCESS_KEY_ID=62714b857ab1aef1df653bae5002a6bacdec99be (例)

AWS_SECRET_ACCESS_KEY=最後が = で終わる生成時にしか表示されない文字列

IAMユーザーを作成して権限を割り当てる

(書きかけ)
ユーザーとグループにはコンパートメントはありませんが、Policyはコンパートメントに属します。

  • アイデンティティ → ユーザー から Create User ボタンを押し、IAM Userを選択して任意のID等を入力してユーザーを作成する。

  • アイデンティティ → グループ から Create Group ボタンを押して、適当な名前のグループを作る(よくわからないけれども、次のPolicyがグループにしか付与できないため

  • グループに先程作成したIAMユーザーを追加する

  • Policy で、任意の名前のpolicyを作成する。

  • そのまま、Policy Builderを使って、Let users write objects to Object Storage BucketsLet users download objects from Object Storage Buckets を追加

  • このままだとバケット内のobjectの削除ができないので、必要であれば、作成したpolicyを選択して Edit Policy Statements を押して、Statement 2 の末尾に request.permission='OBJECT_DELETE' を追記する。

あとは、ユーザーを作った場合と同様に IAMユーザーの 顧客秘密キー を作成してアクセスキーとシークレットキーとして使用すれば良い。

オブジェクトストレージネームスペースの取得

  • コンソールの右上の、ユーザーのアイコンが表示されている部分をクリックし、 テナンシ: <テナント名> というリンクをクリック
  • 表示された画面の中央に表示されている、 オブジェクト・ストレージ・ネームスペース という ID が必要になるのでコピーする。

S3 互換 URL の取得

今まで取得した情報を組み合わせて、アクセス用 URL を組み立てる

https://ネームスペース.compat.objectstorage.リージョン.oraclecloud.com

  • ネームスペースは、上記で取得したオブジェクト・ストレージ・ネームスペース
  • リージョンは、コンソールの URL を見てください。 console.ap-tokyo-1.oraclecloud.com なら ap-tokyo-1 がリージョンです
  • アクセスキー、アクセスシークレットは上記で取得したものを使ってください

蛇足

この内容が判明するまで

検索しまくったり色々として 2 時間くらいをツブしました。。がっくり。
Classic な話とか、旧バージョンとかで操作が大分違うようで、大混乱しました。

オブジェクトストレージネームスペース

オブジェクトストレージネームスペースは、とりあえず テナント名 を入れて接続して、(繋がるには繋がります)

適当にフォルダを作る操作などをすると、エラーメッセージの中に入っている・・・が、普通に拾っても面倒ではないので本当に蛇足。

date: “2016-03-16 15:00:00 +0900”

API 設計をしたときにしくじったこと

今、関わっている Web アプリケーションの API を設計する際に

しくじったことを列挙していくポエムです。

しくじり1 応答メッセージの基本形を決めずに作っちゃった

API を使うクライアントも自分で作る状態だったので、とりあえず

行き当たりばったりで進めていった結果、共通のお作法が存在しない状態に

なってしまった。

しくじり2  HTTP 応答コードだけでエラーを表そうとしてしまった

大抵は、応答コードだけでなんとかなります。ただし、更新時のバリデーション

エラーなど、何がどうエラーだったのかを返そうとすると、応答コードだけでは

全然足りません。そして、エラーの返し方を共通化しておかないと、API によって

エラー発生時の応答が変わってしまい、クライアントを作る人が悲惨です。

しくじり3 業務よりの API と素の DB 操作に近い API が混在しちゃった

これはしくじりなのかまだ決めかねているけれども、なんか微妙なのでしくじりに

しておきます。例えば、テーブル A とそれに紐付く B があったとして、素テーブル

操作っぽい API だと、A を全件取ってくる →A をループして紐付いた B を取得する。

というような処理は割とよくあると思うのですが、これを API として提供した。

性能問題が出るより JOIN して渡した方が良いだろうと。その結果、API の数が

増えてしまい、どれ使ったら良いんだろう?と悩む状態になることがしばしば発生。

API のシンプルさと実務的な側面をどうバランスさせるのかは非常に悩ましい。

美しさだけなら、シンプルな API だけ用意してあとはがんばれ!で良いのですが…

ただのメモ

FreeNAS の NFS を kubernetes ストレージとして使うときに、デフォルト設定だと動きません。(動かない可能性があります)

何をどうすれば良いかメモします。

使用している FreeNAS は 11.2 です

設定

設定は二箇所あります。

設定 1 pool の権限設定

(この手順はおそらく不要)
左側メニューの Storage→Pools を選択し、一覧の右端の ・・・ をクリックして、 edit permission を選択します。

ポイントは、 Mode を全部チェックすることです。ようするにパーミッション 777 です。

設定 2 NFS の設定

左側メニューの Sharing-> Unix(NFS) Shares を選択し、一覧から、該当する NFS 共有の右端の ・・・ を選択して、

Edit を選択します。その後、ADVANCED MODE ボタンをクリックします。

Maproot User 欄が空欄になっていると思いますが、ここに root と入力します。

ここが空欄の場合、自動的に NFS 経由での root でアクセスが nobody に置き換えられてしまい、権限がほぼない。という状態に

なってしまい、kubernetes の Pod 内のファイルの chown 等が失敗してしまいます。

バージョン情報

IntelliJ IDEA Ultimate 2016.2

macOS Sierra

はじめに

Eclipse から IntelliJ IDEA に乗り換えたので変更した設定を列挙していきます。

キーバインド

キーバインドを Eclipse (Mac OS X)に変更

フォーマッタ(JavaDoc)

Editor - Code Style - Java - JavaDoc -> Do not wrap one line comments にチェック

1
2
3
4
5
6
7
`/** 項目名 */
String value;

/**
* 項目名
*/
になるのを防止する。

native2ascii 時、実体参照を小文字にする

ちなみに Properties ファイルはデフォルトでは UTF-8 で書く仕様(普通はこれで OK)

native2ascii したい場合は、

Editor - File Encoinggs -> Transparent native-to-ascii conversion にチェック。

これはプロジェクトごとの設定のようだ。(ということは、 .iml は git 管理した方がよい?)

native2ascii 実施時に、実体参照が大文字で出力されてしまうので、それを小文字(Eclipse と互換)にする為の設定。詳細は下記 Qiita 参照。

http://qiita.com/shiena/items/5143a81f26907475713f

前提

リレーのハードウェアは

これで作ったものを流用しています。実際は、多少バージョンが上がっていますが、基本同じものです。

ハードウェア的なバージョンアップ点は以下

1 入れ物の上にヘッダピンを 3 連*2 で付けて(ホットボンドでネチョ固定)PC ケース側の電源ボタンも使用可能に

2 リレーの片側しか使っていなかったのを両側使うように変更 (適当な GPIO ピンを IN2 に繋いだだけ)

1 をやるのに半田ごてをにぎりましたが、ピンを一本接触させた状態でネチョ固定すれば  半田付け不要だと

思われます。というか何でもいいから 3 本の間で電気が通れば OK

動機

Raspberry Pi を PC のケースに入れるとものすごく邪魔。もう少し小さくならないものか・・・

あと消費電力的にも結構大きいし、これはちょっと。という事で Arduino(ESPr Developer)にしました。

材料

ESPr Developer(ピンソケット実装済) - スイッチサイエンス -
https://www.switch-science.com/catalog/2652/

ジャンパワイヤ(前回と同じ)

ピン接続

  • VOUT -> リレーモジュールの VCC
  • 3V3 -> リレーモジュールの JD-VCC(JD-VCC の隣の方)
  • GND -> リレーモジュールの GND(IN1 の隣の方)
  • IO4 -> リレーモジュールの IN1
  • IO5 -> リレーモジュールの IN2

スケッチ

以下の雰囲気で。実際は、AdvancedWebServer のサンプルを改造して、Web API で

電源 ON/OFF が出来るようにしました。

1
2
3
4
5
6
7
8
9
10
11
12
13
<code class="language-c">#define RELAY_PIN 4

void setup() {
Serial.begin(115200);
Serial.println("setup done");
}

void loop() {
Serial.println("Switch ON");
pinMode(RELAY_PIN, OUTPUT); // これだけでリレーが作動する
delay(3000)
pinMode(RELAY_PIN, INPUT); // これで元に戻る
}

実際に使っている構成

追加した部品

ちなみに、電子ブザーはめちゃくちゃうるさいので圧電ブザーのが良いと思います。安いですし。

あと、秋月電子の店舗に行く場合は、Web ショップの画面の左下にある店舗情報というリンクに、実際モノがどこに置いてあるか細かく書いてあるのでそれをメモってから行くことをオススメします。

店員さんに聞けば場所教えてくれますが、店員さんも同じ画面を見るという。(型番指定時)

部品の接続

  • ESPr Developer の I15 と GND に電子ブザーを接続(ピンソケットに直接差しています)
  • ESPr Developer の I16 と GND に 5mm LED を接続(ピンソケットに直接差しています)

スケッチ

なんか長い感じですが、AdvancedWebServer のスケッチの小改造でしかありません。

ssid , password , mDNS のホスト名は、ご自分のものに書き換えて下さい。

mDNS を有効にしているので、この例だと、http://esp8266.local/ping のような形でアクセスできます。

※ macOS の場合は標準で OK。Linux、Windows の場合は要設定。(Windows10 なら標準?)

というか、文字列定数ってどうやったら定義できるんでしょう?調べたけれどもよくわかりませんでした。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char *ssid = "WIFI-SSID";
const char *password = "WIFI-PSK";

ESP8266WebServer server ( 80 );

#define LED_PIN 16
#define POWER_PIN 4
#define RESET_PIN 5
#define BUZZER_PIN 15

#define LONG 5000
#define SHORT 1000

bool powerSwitch = false;
bool resetSwitch = false;

void setup ( void ) {
pinMode ( LED_PIN, OUTPUT );
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);

digitalWrite ( LED_PIN, HIGH );
digitalWrite ( BUZZER_PIN, LOW );

Serial.begin ( 115200 );
WiFi.begin ( ssid, password );
Serial.println ( "" );

Serial.println ( "WiFi initializing" );

int connection_count = 0;
// Wait for connection
while ( WiFi.status() != WL_CONNECTED ) {
if (connection_count > (10 * 2) ) {
digitalWrite ( BUZZER_PIN, HIGH );
connection_count--;
}
delay ( 500 );

Serial.print ( "." );

connection_count++;

if (connection_count > (10 * 2) ) {
digitalWrite ( BUZZER_PIN, LOW );
delay ( 500 );
Serial.print ( "." );
}
}

Serial.println ( "" );
Serial.print ( "Connected to " );
Serial.println ( ssid );
Serial.print ( "IP address: " );
Serial.println ( WiFi.localIP() );

if ( MDNS.begin ( "esp8266" ) ) {
Serial.println ( "MDNS responder started" );
}

server.on ( "/ping", handlePing );
server.on ( "/power", handlePower );
server.on ( "/reset", handleReset );
server.onNotFound ( handleNotFound );
server.begin();
Serial.println ( "HTTP server started" );

// 接続OK音
digitalWrite ( LED_PIN, LOW );
digitalWrite ( BUZZER_PIN, HIGH );
delay ( 1500 );
digitalWrite ( BUZZER_PIN, LOW );

Serial.println ( "setup complete!" );

}

void loop ( void ) {
server.handleClient();
}

void handleNotFound() {
digitalWrite ( LED_PIN, HIGH );
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";

for ( uint8_t i = 0; i < server.args(); i++ ) {
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
}

server.send ( 404, "text/plain", message );
digitalWrite ( LED_PIN, LOW );
}

void handlePing() {
digitalWrite ( LED_PIN, HIGH );
// digitalWrite(BUZZER_PIN, HIGH);

char temp[400];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;

snprintf ( temp, 400,
"{ \"uptime\": \"%02d:%02d:%02d\", \"uptimeMills\": \"%02d\" }\n"
, hr, min % 60, sec % 60, millis()
);
server.send ( 200, "text/html", temp );
digitalWrite ( LED_PIN, LOW );
// digitalWrite(BUZZER_PIN, LOW );
}

void handlePower() {
if (server.arg("type") == "long") {
doSwitch(LONG, POWER_PIN);
sendJson("POWER", "long");
} else {
doSwitch(SHORT, POWER_PIN);
sendJson("POWER", "short");
}
}

void handleReset() {
doSwitch(SHORT, RESET_PIN);
sendJson("RESET", "short");
}

void sendJson(String target, String duration) {
String json = "";
json += "{ ""result"": ""ok"", ""target"": """ + target + """, ""duration"": """ + duration + """}\n";
server.send ( 200, "application/json", json );
}

void doSwitch(int duration, int pin) {
onoff(true, pin);
delay(duration);
onoff(false, pin);
delay(100); // 一応リレーの切替速度 の問題で待っている。そんな連打はしないけれども
}

void onoff(bool onoff, int pin) {
if (onoff == true) {
Serial.println("Switch ON");
pinMode(pin, OUTPUT);
digitalWrite(BUZZER_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
} else {
Serial.println("Switch OFF");
pinMode(pin, INPUT);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
}

実際の利用方

VPN で LAN に入って、あとは前回の Web アプリを使用して制御を行っています。

今回のスケッチの API も、Raspberry Pi から直接制御していた時と互換にしてあるので、

URL 変更だけで簡単に切替ができました。 消費電力も低いようなので満足です。

実際は、PC ケースに入れて見たら WiFi の電波がつかめなかったり、Zabbix の設定に苦労したりと

色々とあったのですが・・・ 今の所ちゃんと動いてます。

だいぶ古い記事です。

先にお詫び

自分用のメモなので大分荒い部分があります。ごめんなさい。

そしてかなりあやふやです。間違い見つけたら是非教えて下さい。

外部モジュールか、内部モジュールか

内部モジュール

module MyModule {} 形式。別のファイルに分ける必要はない。コンパイル結果を 1 ファイルに

まとめて出力するときに使う。

tsconfig 等で outFile: を指定する場合こちらを使うぽい。 ※実験してません。

import 文を書くと自動的に外部モジュール扱いになる模様。

外部モジュール

1 ファイル= 1 モジュール。コンパイル結果は、 .ts1 ファイルに付き .js 1 ファイル。

使用する際は、 import mymodule = require(‘./MyModule’); みたいな感じで使う。

モジュールのファイル名がモジュール名として扱われる。

MyClass.ts

1
2
3
export class MyClass {
test:string
}

app.ts

1
2
3
import MyClass = require('./MyClass'); // ./入れないとダメ

var test = new MyClass.MyClass(); // 名前がイマイチ

外部モジュールの際、モジュール名の名前空間を切って欲しくない場合の記述

MyClass.ts

1
2
3
4
5
class MyClass {  // export class にしない
test:string
}
export = MyClass; // exportに入れた部分だけexportされる
// exportできるのは1つだけ

app.ts

1
2
import MyClass = require('./MyClass'); // ./入れないとダメ
var test = new MyClass(); // すっきり!

その他覚え書き

所感

基本的には外部モジュールを使っておけば良いんじゃないかなというのが今の所の感想です。

Web 向けだとロード時間の問題とかがあるのでそう単純ではなさそうですが。

Electron であればレンダラプロセスでも標準で require 使えますし、そうでなければ

require.js を入れれば良いのではないかなと。

gulp

開発には gulp とか使うと思うのですが、Typescript のコンパイルは gulp プラグインに

任せない方が幸せになれました。具体的には gulp-shell を使って、

tsconfig -u で tsconfig.json の中の filesGlob に書いたディレクトリ内の

ファイル一覧で files を更新して貰って、tsc -p ./path/to/tsconfig/ で

コンパイルさせると IDE と設定の整合性が取れて良い感じです。

こうすると、 /// reference  タグを書かずに型が参照できて見た目がスッキリします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<code class="language-json:tsconfig.json">{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": true,
"outDir": "../../app/"
},
"filesGlob": [
"*/**/*.ts",
"**/*.tsx",
"**/*.ts"
],
"files": [ 略 ]
}

sourceMap

tsconfig.json で sourceMap: true と指定すると、 .map ファイルが生成されるようになり、

ブラウザの開発者ツールでソースを見た時、Typescript がそのまま表示されるようになる。

確認した限りでは、ソースの Path は相対パスなので、ユーザー名が漏れるような事故は起きなそう。

function

Typescript で function () { } と書くと割と不幸になりがち。

通常はそれほど困ったことにはなりませんが、class 内で callback を指定するときは、

() => {} で書いておかないと、this があらぬ所を差してしまい困ったことになります。

ハマった例を以下にメモしておきます。これ、コンパイル後の出力を見るとすぐにわかるのですが、

() => { } で書くと、自動的に this を _this に保存して、関数内の this を _this に

自動的に置換してくれています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<code class="language-ts:sample.ts">class MyClass {

private instanceVariable = 'ABC';

method1() {
needCallbackMethod(this.callback1); // callback1の書き方によってはNG

needCallbackMethod( () => { this.callback1() }); // OK

needCallbackMethod(function() {
console.log(this.instanceVariable); // NG! this -> Global
}

needCallbackMethod(() => {
console.log(this.instanceVariable); // OK!
}

}

callback1() {
console.log(this.instanceVariable); // NG! this -> Global
}

callback1 = () => {
console.log(this.instanceVariable); // OK!
}

}

参考にした URL

これさえやれば大丈夫! TypeScript の Import が取っ付きにくい人向け

http://qiita.com/armorik83/items/d93fb9c80c489f0fabcf

本文とコメント欄、どちらも参考になります。

TypeScript で複数ファイル構成する 2 つの方法 - teppeis blog

http://teppeis.hatenablog.com/entry/2014/05/typescript-external-modules

export = ; はこちらに書いてありました。

はじめに

knockoutjs + Typescript での ViewModel の書き方が分からなかったので

試行錯誤した結果をまとめてみる。Web アプリケーション向けです。

注意:書いた人は Typescript 初心者です。間違ってたらコメント下さい。

参考にしたページ(英語):

https://github.com/Microsoft/TypeScript/wiki/'this'-in-TypeScript

書き方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
///<reference path="../../typings/jquery/jquery.d.ts"/>
///<reference path="../../typings/knockout/knockout.d.ts"/>
///<reference path="../../typings/knockout.mapping/knockout.mapping.d.ts"/>
// ライブラリの型宣言ファイル取込。

// 外部変数の宣言(html直書きのscriptの変数を参照するとか) …注1
declare var nextUrl: String;

//
class HogeViewModel {
// koお約束の self = this はいらない

// クラス変数宣言。 self.hoge = ko.observable(true);
hoge:knockoutObservable<boolean> = ko.observable(true);

// 普通のクラスメソッド。これは普通のTypescript
hogeMethod(layer1:any):void {
(略)
}

// イベントハンドラにする場合・・・注2
eventHandler = (layer1:any):void => {
(略)
}

}

注1 外部変数

例えば、遷移先 URL とか。次の例でいうと nextUrl

1
2
3
4
5
<!-- html(thymeleaf)内だと思って下さい -->
<script th:inline="javascript">
var nextUrl = /*[[@{/next/url}]]*/ '/app/next/url';
// さすがにこれはts内には埋め込めない
</script>

注2 イベントハンドラにする場合

イベントハンドラにする場合とは、例えば data-bind=”click: eventHandler” とか、

jQuery.on するとか、そういう場合のことを指す。

この場合、書き方をしないと、this がインスタンスではなく他のものを指してしまう。

# data-bind=click だとそれに紐付いたオブジェクトのインスタンスになったりとか。

その他

今まで self.hogehoge で参照していたものは全て、 this.hogehoge に書き換えが

必要。慣れれば頭を使わずに js -> ts にコンバート出来るかもしれません。

ライブラリ用の型宣言ファイルについて

https://github.com/DefinitelyTyped/DefinitelyTyped

ここからダウンロードすれば良い。が。さすがに gibhub から直接探すのは辛いので、それ用の

ツールを使う。個人的には dtsm がオススメ。コマンドが yum とか apt-get ぽくて慣れやすい

dtsm

検索して出てきても情報量 0 なポエム。

Fujitsu MX130 時代

Opteron 3260 に CPU を差し替えて使用していた。

開発用の VM を起動するのにしか使っていなかったのでそれほど面白いことはしてない。

面白いと言えば、ヒートシンクに金属製の洗濯ばさみを付けてた。これをするとチップセットが冷えて

ファンの回転数が下がるというおもしろい工夫だった。これをしたら本当に静かになって大変助かった。

そのまま、お仕事の事務所用 VM ホストとして現在も活躍中。小さいのはえらい。

あと、無駄に 8 コアに見える(4C8T)

Core i7 860 時代

2014 年ごろ。鼻毛鯖の CPU を交換してサーバーにしていた時代。

途中で CPU が Xeon X3450 に交換されている(が性能はまったく変わらないかむしろおちたくらい)

ケースが元々のケースで使用していたが HAF932 を貰った為、ケースだけ HAF932 に。

以降、電源が変更されたりして、徐々に元の部品がなくなっていった。

動作させていた機能

  • Chinachu
  • ファイルサーバー

構成

Hypervisor: ESXi

ストレージ: WD RED 2TB * 3 (途中で 3TB * 3 に変更)

起動は USB から行っていた記憶。

メモリも 16GB 程度だったので VM は数台だったと思う。

ハイパーバイザーを Xen Server とか Proxmox VE とか Windows Server(hyper-v)に変更して色々実験していた。

RAID カード沼

いろいろな RAID カードを買っては試した。感想は以下。

  • Dell Perc 6i

割と普通に動いたけど、確かピンのマスクが必要だった記憶。

ESXi でもちゃんとドライバが当たった…はず。

http://yannickdekoeijer.blogspot.com/2012/04/modding-dell-perc-6-sas-raidcontroller.html

  • HP Smart Array P410

ESXi だと、HP のサーバーじゃないとドライバが入らない。Windows Server だと普通に動く。なので Windows   Server の時使ってた。

これもピンをマスクしたような…。 RAID カード全般にそうだけど、差すと起動がとても遅くなるのつらい。

バッテリーがついてなかったので、ライトバックができなくてつらかった。

  • NEC N8103-117 (LSI 8708EM2)

バッテリつき。割と良かった。 よかったが、3TB の HDD に対応しておらず、残念ながら退役させた。

  • まとめ

ESXi だと割と状態の監視が厳しい(と言っても OK か DEGRADE かくらいは分かる)。Windows Server だとその辺はさすがに完備。

でも、色々と ESXi は便利だった…

Core i5 4570 時代

いわゆる自作機。Core i7 はコスパ悪いので基本的には選ばない。のお気持ち。

動作させていた VM

  • Chinachu
  • ファイルサーバー
  • fastladder
  • Mastodon

ESXi

前からの構成とほぼ同じ。 RAID カードは確か Perc6i だった記憶。

安定 of 安定。特に変更する必要はなかったが、やっぱり Hypervisor の入替はやっていた模様。

結局 ESXi に戻るみたいな。多分このサーバーから Mastodon の運用始めてるはず。

Ryzen 7 1700 時代 (現行)

買う時、かなりの博打で買った構成。というのも、当時の Ryzen はメモリとの相性がキツくて、

動くか動かないかわからない。推奨のメモリは、マザボメーカーの動作確認済みメモリだけ。

みたいな状態。

  • Ryzen 1700
  • ASRock X370 Gaming K4 (Intel NIC が乗っているから選んだものの Windows Server のドライバがない。という罠)
  • Corsair Vengeance LPX 16GB * 2

Windows Server 2019 第一期

ESXi を使いたかったが、Ryzen だと PCI パススルーが上手く行かなかったため、諦めて Windows Server で組む羽目になった。

全ての VM が機能毎に一個ずつ存在する構成。

VM たち

Chinachu

これが問題で Windows Server になった。今までは PT3 をパススルーしていたが、それが不可能になったので

ホスト側で Mirakurun を動かし、そこに接続する形で構成した。安定して動いているのでまぁ良い。

Mastodon

本番インスタンスとテストインスタンスがそれぞれ別 VM。Non docker で立てていた。

また、PostgreSQL を独立した VM として切り出して、そこに依存することでさらに加速させた。

Minio

minio 専用 VM を立てていた。

fastladder

最初は non-docker だったが、docker にした。昔から mysql で構成していたのでそのまま。

zabbix

mysql と組み合わせて作っていた。監視対象が同一 PC 内にいるってどうなのよ?という問題があったので、

Raspberry Pi (microSD カード運用)→(壊れたので SSD 運用)→(性能不足?)→Jetson Nano

→(Jetson を zabbix に使うのダメでしょ)→Raspberry Pi(64bit, postgresql)

と、さすらっている。

ElasticSearch

ログ解析というのをやりたくて導入。これが兎にも角にもメモリ食いで、色々と悲劇を生んだ。

elasticsearch + Logstash + Kibana というお約束構成だった、全部を同一 VM に入れた為に

メモリ量が 4GB でも足りないという状態になり、大変つらかった。

ストレージ

Adaptec 6805T + BBWC を購入して、RAID10 を構成していた。WD RED でも、ストライピングすると

割と早いのでとても良かった。

Windows Server 2019 第二期 docker

この頃は、docker が正直言って本番環境に投入するものではないと思っていた。理由は不安定だから。

CentOS5 に docker を入れて、Web アプリを動かしたら 12 日でカーネルパニックした苦い思い出がある。

※ CentOS5 のカーネルが古すぎただけだと思う。Ubuntu16.04LTS にしたら安定したので。

※ この時以来、サーバーは Ubuntu で構成するようになった。

この時期、SSD を買いまくった記憶がある。サービス動かすのに容量より球数が欲しくて、

兎にも角にも毎月のように SSD を投入したような。(4 台まで増えました)

VM たち

基本的に VM は同じだが、全ての VM を docker 化した。

最初は、Mastodon のバージョンアップ時にサービスが停止する時間がながいのが嫌だったんだけれども、

※ assets:precompile がメモリを食いまくる&長いのでその間サービスを停止していた。

docker 化してイメージを作ってしまえば、そこの入替と db:migrate だけでバージョンが上げられるので

大変楽になった。この時期から、Mastodon は自動的に Master 追従するようになった。

そして、docker のイメージをビルドする為のサーバーが VM として追加された。

この時点で、メモリがかなり逼迫しており、30GB/32GB くらい常時使用しているような状態だった。

VM をシャットダウンするとメモリ不足で起動できないとか、サーバーで Firefox 起動しっぱなしだと

スワップ始まっちゃうとか、本当にギリギリだった。

docker swarm を入れて上手いことやればもっとリソースを詰めることができた(検討はした)

が、ストレージが大げさになって面倒だなぁ。ということでやらなかった。

Windows Server 2019 第三期 kubernetes

kubernetes を入れれば、docker コンテナの管理が楽になって、システムリソースが有効に使える。

しかも、ナウでトレンディ。将来の為にもこれはやっておくべきだろう。ということで構成変更。

この時、財団は ThinkCentre Tiny M73p で臨時にホストしていた。Hyper-V でよかったー

と思った瞬間ではある。

で、当然メモリが足りないのでついに増設を決意した。 このマザーボード、メモリを増やすと

速度が落ちるという仕様で、しかも動くかどうか博打だったが、なぜか XMP を有効にするとメモリが

動作して、速度も早いまま。それ以外では動かないというワケの分からない状態で動いている。

VM

docker イメージビルド

kubernetes 内で kaniko を使ってビルドしても良かったが、(テストして動くことは確認した)

唐突にワーカーノードに負荷がかかるのは嬉しくないので独立させている。

Chinachu

これは他にあんまり依存してほしくないので独立した VM としている

kubernetes

VM の構成は、kubernetes master / worker * 3

kubernetes master は 2core / 2GB RAM

worker は 4core / 8GB RAM

バージョンは最新を追いかけている。 kubeadm によるセットアップ。

ストレージ

NFS

NFS のできるだけ新しい実装が欲しかったのと、使ってみたかったので、Arch Linux で構築していた。

問題なく動作していたが、あまりに普通であるが故に色々といじられる対象となる

GlusterFS(失敗、切り戻し)

GlusterFS on kubernetes で構築してみた。

https://qiita.com/yakumo/items/3562be29084ca09018d3

しかし、SSD で組んだにもかかわらず速度的に 30MB/s 程度しか出せず、メリットと速度を天秤にかけた結果切り戻しに。

動作自体はちゃんと動いていたので問題はなさそうだが、次に試すなら Ceph にすると思う。

(Ceph にすれば Minio も廃止できるので)

ダイナミックボリューム(RAID-5、失敗)

元々は RAID カードがトラブったのが嫌になってしまい、SATA オンリーに切り替えた。

その際、ポート数が足りない為、HDD4 台 →3 台になってしまって RAID1 で 2 台、素が 1 台という納得いかない

構成で使っていた。結果、RAID1 側の空き容量が偏って減ってしまいちょっと嫌だなという状態に。

なので、RAID5(パリティあるの本当はあんまりうれしくないが)を構成しようとして、

Windows Server の機能の RAID-5 を組んでみた。…結果、書込速度が 35MB/s 程度になってしまいなんだかなぁ…

ググってみると記憶域スペースならもっと早いらしい。ということで移行断念した。

記憶域スペース (parity、RAID-5 相当、失敗)

まず最初に、サーバーマネージャから構成しようとすると Parity が構成できない。

powershell を使って構成したら上手く構成できた…が。

データのコピー中に Windows Update で再起動がかかったのか、翌朝起きてみたら

ディスクがオフラインになっていた。

…正直、これを使い続けるのは怖いので撤退。移行は失敗とした。

FreeNAS

2019/10/20 導入。 ZFS は以前に導入していた時期があり、信頼はできるのでもうこれでいこうと導入。

Hyper-V にも RDM(Raw Device Mapping) があることをしり、HDD 3 台を全部任せることに。

ZFS はさすがに普通に動いてくれたので大変助かった。

そして、FreeNAS で NFS が使えるので SSD も FreeNAS に任せて、NFS サーバーを停止したのであった。

内部ネットワーク

flannel、MetalLB を使用している。

外部ネットワーク

RTX 期

RTX1200 を使用。 LAN1 が家庭用セグメント、LAN2 が WAN、LAN3 がサーバーセグメントという使い分けをしていた。

これは、RTX1000 とか 1100 の時代からの config を引き継いで使っていた。LAN1 -> LAN3 は NAT で接続する形。

歴代の RTX を使ってきてホント不満がなかった。RTX1200 の筐体がいっきに大きくなったのは正直つらい。

その他、EdgeRouter Lite 3 を試したり、OpenWRT を試したりしてる。

VyOS 期 (2019/10/27)

RTX1200 が大きすぎて置き場所に困ったのと、サーバーの LAN ポートを 1 ポート開放(ドライバ入れてなかった)

に伴い、RTX1200 を無くしてもいけるなという気分で変更された。実利的には、OpenVPN の終端を行う VM が

1core 512MB で構築されていて、その VM の割り当て分を VyOS に変えることで実質無料みたいな状態で処理できている。

LAN の構成そのものは変わっておらず、 zone は internet, intra , server と cloud の 4 つにしてある。

OpenVPN の終端がルーターに移動したので、OpenVPN の先にいるフロントも統合的に扱えるようになって

むしろスッキリした感じである。

Mastodon 上での助言で、intra->server の NAT はやめて、ファイヤウォールによるアクセス制御に変更した。

速度的には、RTX1200 より向上したように思えるが、速度的にはほぼ変わっていない(VDSL なので 100Mbps 上限)

OpenWRT 期(2019/10/29)

VyOS 期が短いように思えるが、 tootctl domains crawl を実行するとネットワークが不安定(外部接続不可)

になるというトラブルが発生してどうにかしようとして置き換えたもの。

実はこのトラブルが DS-Lite 起因ではないかという疑惑があり、無駄な置き換えだったかもしれない。

ある意味、GUI で設定できて楽と言えば楽。OpenVPN は GUI より設定ファイルいじった方が早い気もするが…

WSR-1166DHP を使用しているが(無線 LAN は無効)、CPU 使用率が意外と高いのでもう少し良いルーターが必要かもしれない。