麦星 - arcturus technologies- 

クラウド関連情報とデータサイエンス的な何かを発信しています

Function Compute でOSSのバケットサイズを計測

ども、最近、OSSと戯れる機会が多い、うし@tangniuwanです。

定期的にOSSバケットサイズ(ストレージの容量)が知りたいケースがあったのですが、 サンプルやら、ネットの海やらを探しても、これといった情報が見つからず…

しゃーないので、GitHubSDK(aliyun-oss-php-sdk)を漁り、
サイズ取得メソッドが実装されていたのを発見し、あれやこれやで無事、バケットサイズが計測できましたので
発見までの経緯と、そのソースコードを共有させて頂きます。

経緯

通知の方法として、
「Email + DingTalk (Info)」が使用できるため
当初は、Cloud Monitorのアラームサービスのルール作成から設定できないかな?と思いましが、
Cloud Monitorで設定できる項目をよくよく確認すると、バケットサイズに関連するものが無く、
ファイル数やレイテンシーなどに関するものが多数ありました。

という事で、Cloud Monitorを諦め、自前で作ることにしました。 ちなみに、会社の昼休みと退勤後のオンライン飲み会の時間を使って、以下のコードを書き上げました。

やったこと

最初にやったこと

以下、 URLのドキュメントセンターで、オブジェクト(ファイル)一覧を取得する方法を確認しました。

jp.alibabacloud.com

以下は、オブジェクト(ファイル)一覧を取得するサンプルコードの引用です。
諸々設定して素直に実行すると、指定したバケット内のファイル一覧が表示できます。

<? php
if (is_file( _DIR . '/../ autoload.php')) {
require_once _DIR . '/../ autoload.php';
}
if (is_file( _
DIR__ . '/../ vendor/autoload.php')) {
require_once _
DIR__ . '/../ vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;

// It is highly risky to log on with AccessKey of an Alibaba Cloud account because the account has permissions on all the APIs in OSS. We recommend that you log on as a RAM user to access APIs or perform routine operations and maintenance. To create a RAM account, log on to https://ram.console.aliyun.com.
$accessKeyId = "";
$accessKeySecret = "";
// This example uses endpoint China East 1 (Hangzhou). Specify the actual endpoint based on your requirements.
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
$bucket= "";

$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

while (true) {
 try {
  $listObjectInfo = $ossClient->listObjects($bucket, $options);
 } catch (OssException $e) {
  printf( __FUNCTION__ . ": FAILED\n");
  printf($e->getMessage() . "\n");
  return;
 }
// Obtain the nextMarker. Obtain the object list from the object next to the last object read by listObjects.
 $nextMarker = $listObjectInfo->getNextMarker();
 $listObject = $listObjectInfo->getObjectList();
 $listPrefix = $listObjectInfo->getPrefixList();
 if (! empty($listObject)) {
  print("objectList:\n");
  foreach ($listObject as $objectInfo) {
   print($objectInfo->getKey() . "\n");   }
 }
 if (! empty($listPrefix)) {
  print("prefixList: \n");
  foreach ($listPrefix as $prefixInfo) {
  print($prefixInfo->getPrefix() . "\n");
  }
 }
 if ($nextMarker === '') {
  break;
 }
}

次にやったこと

上のソースコード上で、

    $listObject = $listObjectInfo->getObjectList();    

という構文があり、ファイルリストを取得し、変数「 $listObject」へ格納しています。
その後、「$listObject 」をforeach でぐるぐるループしているのが分かります。

    foreach ($listObject as $objectInfo) {  
        print($objectInfo->getKey() . "\n");  
    }  

ここで、変数「$objectInfo」は、ファイルを扱っているモジュールなので、
実はファイルのサイズ情報とか持ってるんじゃね?という疑惑がありSDKを調べるに至りました。

結果、案の定、GitHub上の「objectInfo」モデルのソースコードがあり、確認するとサイズ情報を保持していました。  

※確認すると「getSize()」なるメソッドを保持しています。
f:id:tangniu:20210130022551p:plain

以下は、該当クラスのページURL
github.com

という事で、サンプルソースを以下の様に書き換えます。 (太字の部分が上部のソースからの変更点。あとは、不要なコードを削除しています。)

<? php

use OSS\OssClient;
use OSS\Core\OssException;

$accessKeyId = "";
$accessKeySecret = "";
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
$bucket= "";

$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

$buketSize =0;
while (true) {
 try {
  $listObjectInfo = $ossClient->listObjects($bucket, $options);
 } catch (OssException $e) {
  printf( __FUNCTION__ . ": FAILED\n");
  printf($e->getMessage() . "\n");
  return;
 }
 $nextMarker = $listObjectInfo->getNextMarker();
 $listObject = $listObjectInfo->getObjectList();
 if (! empty($listObject)) {
  print("objectList:\n");
  foreach ($listObject as $objectInfo) {
   print($objectInfo->getSize() . "\n");
   $buketSize += (float)$objectInfo->getSize() / 1024 / 1024;
  }
 }
 if ($nextMarker === '') {
  break;
 }
}

あとは、変数「$buketSize」にファイルサイズを加算すると、バケットのトータルのサイズが取得できます。
という事で、ファイルサイズが取得出来たら、あとは、メールで送付するなり、Slackに通知するなりして、 CRONや、Function Compute のタイマートリガーを設定すれば、定期的にバケットサイズ情報が通知されます。

最後まで見て頂いてありがとうございます。

でわ

サーバーレスなWEBアプリケーション

ども、うし@tangniuwanです。

先日、サーバーレス(Function Compute)でフレームワークを使用したWEBアプリケーションを試しに構築してみたもの
若干、削除に手間取ったので、情報共有がてら削除の手順について記事にしました。

色んな言語とフレームワークが使えるので、調子こいて結構な数のWEBアプリケーションを作ってしまいました。。 (かなり便利なので、使わない手はないです。)ただ、消すのは面倒。。

ちなみに、使用可能な言語と、フレームワークは以下になります。
基本、ボタン1つ2つクリックするとデプロイまで出来ます。

言語 ランタイム フレームワーク 関連URL 備考
Node.JS 6.10 / 8.9.0 / 10.15.3 Express https://expressjs.com/ja/
Nuxt.js https://nextjs.org/
Nuxt.js https://ja.nuxtjs.org/
Egg.js https://eggjs.org/ 中国産
Java Java8 Spring Boot(jar) https://spring.pleiades.io/
Tomcat/Jetty(war) https://github.com/eclipse/jetty.project
Go 不明 Gin https://gin-gonic.com/
Beego https://beego.me/
PHP 7.2.7 Laravel http://laravel.jp/
ThinkPHP https://github.com/top-think 中国産
Python 2.7/3.6 n/a コード(ZIP )をアップロードして起動コマンドとリスナーポートを指定すれば利用可能になります。
.NET Core .NET Core 2.1 n/a コード(ZIP )をアップロードして起動コマンドとリスナーポートを指定すれば利用可能になります。
Container n/a n/a ACR(Alibaba Cloud Container Registry)からコンテナイメージを指定してデプロイするだけで利用可能です。

※参考:https://www.alibabacloud.com/help/doc-detail/74712.htm

こう見ると、今までは、アジア圏以外のフレームワークが主流だったのが、中国産のフレームワークが増えてきたなーという印象です。

フレームワークを使用したWEBアプリケーションの削除

さて、本題の削除方法についてです。

個人的には、
Function Compute に限らず、一つ一つのプロダクトや、コマンドなどを理解するより構成を理解する方が重要だと認識しています。
そして、この「Function Compute」 を利用した「フレームワークを使用したWEBアプリケーション」の構成は以下の様な構成になっています。

構成を理解する

構成は以下のような感じです。(間違ってたらご容赦ください。)

フレームワークを使用したWEBアプリケーション」は、ボタン1つ2つで作成できるのですが
削除は以下の構成図の小さい単位(コード・トリガー||バージョン・エイリアス<関数<サービス||カスタムドメイン)から削除し、
最終的にアプリケーションを削除します。

f:id:tangniu:20210130001147p:plain

削除手順

  1. 前述の通り、まず、トリガーを削除します。
    f:id:tangniu:20210130002719p:plain

  2. バージョンを削除します。
    f:id:tangniu:20210130002722p:plain
    f:id:tangniu:20210130002725p:plain

  3. エイリアスを削除します。
    f:id:tangniu:20210130002728p:plain
    f:id:tangniu:20210130002731p:plain

  4. 関数を削除します。
    f:id:tangniu:20210130002734p:plain
    f:id:tangniu:20210130002737p:plain

  5. サービスを削除します。
    複数のサービスがある場合、上記1~5の手順を繰り返します。
    f:id:tangniu:20210130002739p:plain
    f:id:tangniu:20210130002743p:plain

  6. カスタムドメインを削除します。
    f:id:tangniu:20210130003941p:plain

  7. プロダクトが異なるのですが、Resource Orchestration Service (ROS)に
    スタックが生成されているので削除(リリース)します。
    f:id:tangniu:20210130004416p:plain

以上で綺麗に削除ができました。

作るのは簡単でも削除はなかなか面倒いですね。。

でわ

OSS(Object Storage Service)のSDK(aliyun-oss-php-sdk)を修正した話

ども、うし@tangniuwanです。

とある案件で、アリババクラウドOSS(Object Storage Service)を使用させて頂いたのですが、
SDK(aliyun-oss-php-sdk)の「uploadFile」メソッドに不具合があったので修正しました。

サクッと修正できるかな?と思ったら、何気に苦労したなーということでブログの記事にさせて頂きました。

 
※ちなみに現状は、
以下、本家のリポジトリをフォークして修正、Unitテストまで終わった所になります。

github.com

そしてフォークして修正したリポジトリは以下になります。

github.com

OSSAPIでやったこと

WEBサーバから、OSS(Object Storage Service)に対し、SDKを利用しファイルをアップロードしました。

参考にしたのは、以下のソースコードで、ドキュメントセンターにある
簡易アップロード(ローカルファイルのアップロード)
に記載されているものです。

※以下に記載しているものは、ちょっと見やすく整形しています。

<? php
require_once __DIR__ . '/vendor/autoload.php';

use OSS\OssClient;
use OSS\Core\OssException;

$accessKeyId = "<yourAccessKeyId>";
$accessKeySecret = "<yourAccessKeySecret>";
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
$object = "<yourObjectName>";
$filePath = "<yourLocalFile>";

try
{
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
    $ossClient->uploadFile($bucket, $object, $filePath);
} 
catch(OssException $e) 
{
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": OK" . "\n");

不具合の内容

上記ソースコードで、
変数「 $filePath 」に日本語のファイル名を設定すると、中国語と誤解釈し、
GBKへエンコーディングしてエラーになる。というもの。。
しかも、これは、Windows OSの場合のみ発生します。

具体的には、
上記のソースコードに諸々設定した上で、以下の様に変数「 $filePath 」へ日本語文字列を設定し、
実行すると、そんなファイルは無いよ!とエラーになります。

// 設定値  
$filePath = "北海道testテスト.png";  
  
// 実行結果  
testƥ.png file does not exist  

見ていただくとわかる通り、
日本語が消えてしまい。文字化けを起こしたりしています。

こりゃいかん。とのことでSDKを修正した内容を以下に

原因

まず、原因
OssUtil.php(PATH: /oss-sdk-php/src/OSS/Core/OssUtil.php)の341行目にある以下の構文で、
設定したファイル名を、GBKにエンコードしています。
この際、中国語で且つ、WindowsOSか?を判定していますが、
日本語「北海道testテスト.png」を設定していても中国語と判定されます。
では何故、日本語を指定しているにも関わらず、「chkChinese」メソッドで、中国語と判定されるのか?

※メソッドの引数「$file_path」に、設定した「北海道testテスト.png」が代入されます。

    /**
     * Encodes the file path from GBK to UTF-8.
     * The default encoding in Windows is GBK. 
     * And if the file path is in Chinese, the file would not be found without the transcoding to UTF-8.
     *
     * @param $file_path
     * @return string
     */
    public static function encodePath($file_path)
    {
        if (self::chkChinese($file_path) && self::isWin()) {
            $file_path = iconv('utf-8', 'gbk', $file_path);
        }
        return $file_path;
    }

という事で、さらに「chkChinese」メソッド(以下ソースコード)を確認すると
preg_match関数で「/[\x80-\xff]./」が指定されています。
  
これは簡単に言うと、非ASCII文字範囲で、
2バイト文字を含まない半角の英数字、記号、制御記号(空白等)か?ということを判定しています。

つまり、1バイト以外は中国語として認識します。。ーみたない判定をしちゃってます。
(なかなか、豪快で男気に溢れています)

    /**
     * Check whether the string includes any chinese character
     *
     * @param $str
     * @return int
     */
    public static function chkChinese($str)
    {
        return preg_match('/[\x80-\xff]./', $str);
    }

原因が判明したので、この「chkChinese」を修正していきます。
とりあえず、日本語だけでもエンコードされない様に。とのことで
先程の「encodePath」メソッドで日本語だったらエンコードされない様にすれば良い。くらいに考えていましたが、 ここで大きな間違いに気づきます。

地味に苦労した内容

何に苦労しかと言うと、中国語には、繁体字簡体字があります。
これは皆さんご存じだと思います。
この繁体字簡体字には、日本語と被る文字が沢山、それは沢山あります。

例えば、「作」という漢字は、日本語にも繁体字にも簡体字にも存在します。
また「義」という漢字は、日本語と繁体字にはあるけど、簡体字には違う文字として存在していたりします。

例)パターン一覧

日本語 繁体字 簡体字 パターン
三者三様
三者同一
日本語だけ違う
繁体字だけ違う
簡体字だけ違う

参考:繁体字と簡体字と日本語を区別する - Qiita

しかも、 CJK統合漢字 - Wikipedia と言うやつがあり、
例えば「」という漢字は、中国語、日本語、朝鮮語でも、言語を問わず同じコード。。

つまり、例えば「作義.txt」というファイルがあった場合、日本語とも、繁体字とも取れ、
一概に日本語文字と判定ができないってことになります。

※ちなみに、ソースコード上に 「GB 2312 - Wikipedia」というものがありますが、調べると簡体字のみサポートしている。。とのこと

修正内容

という事で、「chkChinese」メソッドの修正内容を以下の方針としコーディングしました。

また、幸い?「checkChar」(GBK=「繁体字簡体字」を判定するメソッド)や、
「isGb2312」(簡体字を判定するメソッド)が既に実装されており、流用させて頂きました。

  • 半角文字(1バイトの文字)を削除
  • 残った文字列が、日本語にしかない文字(ひらがな・カタカナ・漢字)で構成されてたら「日本語」
  • 更に繁体字か、簡体字で構成されているかを確認
    /**
     * Check whether the string includes any chinese character
     *
     * @param $str
     * @return int
     */
    public static function chkChinese($str)
    {
        // 1byte character delete 
        $str =  preg_replace( "/[\x20-\x7E]+/" , "" , $str );

        // chk japanese character only
        if( preg_match("/^[ぁ-んァ-ヶ一-龠々]+$/u" , $str ) ) return false;

        //Checks if the string is encoded by GBK
        return checkChar( $str );
    }

朝鮮語など、他言語での動作は不明ですが、
ユニットテストが通ったので、これでファイル名に日本語が含まれててもエラー無く、アップロードが出来るようになりました。
簡易版としては、取りあえずOKで、日本語で使用する分には問題なく動作するかな?と思います。

また、繁体字簡体字を判定する正規表現メソッドも作成しときましたので、
別途、ブランチ作成しときたいと思います。

とりあえず、イシューたてて、プルリクしときたいと思います。

最後まで読んで頂いてありがとうございます。

でわ