赤枠部分は Calamari コードで実装された部分、赤枠以外の部分は Calamari で実装されていないオープンソースフレームワークです。
Cephserver ノードにインストールされるコンポーネントには、Diamond と Salt-minion が含まれます。 Diamond は、監視データの収集を担当します。上図では、各タイプのデータがコレクターとして機能するほか、主要なリソースの使用状況やパフォーマンスのデータも収集できます。 、CPU、メモリ、ネットワーク、I/O 負荷、ディスク メトリクスを含みます。 Collector はローカル コマンド ラインを使用してデータを収集し、それを Graphite に報告します。
Graphite はエンタープライズレベルの監視ツールであるだけでなく、リアルタイムで描画することもできます。カーボンキャッシュは、Python で実装された拡張性の高いイベント駆動型 I/O アーキテクチャのバックエンド プロセスであり、多数のクライアントと効果的に通信し、低オーバーヘッドで大量のビジネスを処理できます。
Whisper は RRDtool に似ており、特別な形式で保存されたファイル データ (時間データ ポイント データ) を操作および取得するためのアプリケーション用のデータベース開発ライブラリを提供します。Whisper の最も基本的な操作は、新しい Whisper ファイルを作成し、更新し、新しいファイルを書き込むことです。データ ポイントはファイルに保存され、取得されたデータ ポイントは、ユーザーが URL を介して画像を生成するために使用されるユーザー インターフェイスです。
Calamari は、Saltstack を使用して Calamari サーバーと Ceph サーバーノード間の通信を行います。 Saltstackは、ChefやPuppetと同様の機能を備えたオープンソースの自動運用保守管理ツールです。 Salt-master は、指定された Salt-minion に指示を送信して、Cpeh クラスターの管理を完了します。Salt-minion は、Ceph サーバーノードのインストール後に、マスターから ceph.py ファイルを同期してインストールします。このファイルには、Ceph 操作用の API が含まれています。 librados またはコマンドラインを呼び出して、最終的に Ceph Cluster と通信します。
calamari_rest は Calamari REST API を提供します。詳細なインターフェイスについては公式ドキュメントを参照してください。 Ceph の REST API は低レベルのインターフェースであり、各 URL は同等の CEPH CLI に直接マッピングされます。Calamari REST API は高レベルのインターフェースを提供し、API ユーザーは GET/POST/PATCH メソッドを使用してオブジェクトを操作できます。それらの主な違いは、Ceph の REST API のユーザーは Ceph 自体をよく知っている必要があるのに対し、Calamari の REST API は Ceph リソースの記述に近いため、上位層のアプリケーションを呼び出すのにより適していることです。
cthulhu は、Calamari Server のサービス層として理解できます。上位側で API のインターフェイスを提供し、下位側で Salt-master を呼び出します。
calamari_clients は、インストール プロセス中に、Calamari サーバーが最初に opt/calamari/webapp ディレクトリを作成し、webapp/calamari の下に manager.py (django 設定) ファイルを入力します。これを opt/calamari/webapp の下に配置して、UI アクセス ページを提供します。
calamari-web パッケージの下のファイルは、calamari_rest および calamari_clients によって使用されるすべての Web 関連の構成を提供します。Calamari をベースにした新機能を開発します。主に以下のモジュールに分かれています。この部分には、Rest-API 部分、Cthulhu、および Salt クライアント拡張機能が含まれます。新しい関数を拡張するための基本的な手順は次のとおりです:
>> URL モジュールを展開し、対応する応答インターフェイス パラメーターと、ViewSet 内の対応する応答インターフェイスを決定します。
>> ViewSet のいくつかのインターフェイスの実装を完了します。この部分には主に cthulhu との対話、データ情報の取得方法が含まれます。場合によっては、シリアライザーでのオブジェクトのシリアル化操作も取得する必要があります。
>> バックグラウンドの rpc.py で対応する型の展開を完了します。この部分は主にいくつかの事後操作に使用されます。
>> 操作を提供する一部の関数は、作成、更新、削除などの操作をサポートする必要があり、対応する RequestFactory を提供する必要があります。 cluster_monitor.py では、対応する RequestFactory をコードに追加する必要があります。
>> 対応する RequestFactory クラスの記述を完了します。この部分は主にコマンド操作のカプセル化を完了します。そして、対応するリクエスト操作を構築します。
>gt;>salt-minion の拡張子、この部分は主に ceph.py ファイルの拡張子用ですが、もちろん、新しい xxx.py ファイルも提供できます。
次に、PG の制御と操作を例に説明します。
現在、Calmamari は Rest-API 形式を採用しており、この部分は Django の Rest-Framework フレームワークによってサポートされています。 Django は URL とコードロジックを分離する実装方法を採用しているため、URL を独立して展開することができます。
次の PG 関連の URL をrest-api/calamari-rest/urls/v2.py に追加します:
url(r'^cluster/(?P
url(r'^cluster/(?P
calamari_rest.views.v2. .as_view({'post': 'apply'}),
name='cluster-pool-pg-control'),
上記は 2 つの URL を定義しています:
api/v2/cluster/ xxxx/ pool/x/pg
api/v2/cluster/xxxx/pool/x/pg/xx/command/xxx
上記2つのURLはそれぞれPgViewSetのインターフェースを指定しており、URLのgetメソッドがリストに相当しますインターフェース 。 post インターフェイスに対応する apply インターフェイス。これら 2 つのインターフェイスは PgViewSet に実装する必要があります。
URL を拡張した後の次のステップは、対応する応答インターフェイスを拡張することです。拡張機能のこの部分は主に、URL で指定されたインターフェイス クラスを実装します。以前の PG では、取得コマンドと操作コマンドという 2 つの異なるインターフェイスが指定されていました。対応するコード パスは /rest-api/calamari-rest/view/v2.py です。具体的なコードは次のとおりです。 ):
serializer_class= PgSerializer
deflist(self, request, fsid, pool_id):
poolName = self.client.get(fsid, POOL, int(pool_id))['pool_name']
pg_summary = self.client.get_sync_object(fsid, Pgsummary.str)
pg_pools = pg_summary['pg_pools']['by_pool'][int(pool_id)]
forpg in pg_pools:
pg['pool'] = poolName
return Response(PgSerializer(pg_pools, many=True).data)
defapply(self, request, fsid, pool_id, pg_id, command):
return Response(self.client.apply(fsid, PG) , pg_id, command), status=202)
上記の実装から、コードが 2 つのインターフェイス、つまり、前の get 操作と post 操作に対応する list インターフェイスと apply インターフェイスを実装していることがわかります。上記の 2 つの操作は、背景のクトゥルフと対話します。パラメータを取得してリクエストを送信します。返されるコンテンツにも特定の違いがあります。
同時に、リストインターフェイス、つまりrest-api/calamari-rest/serializer/v2.pyに実装されているPgSerializerでシリアル化設定が行われます。
1.2.1 シリアル化操作
class PgSerializer(serializers.Serializer):
classMeta:
fields = ('id', 'pool', 'state', 'up', 'acting', 'up_primary ' ,'acting_primary')
id =serializers.CharField(source='pgid')
pool =serializers.CharField(help_text='プール名')
state =serializers.CharField(source='state', help_text = 'pg state')
up =serializers.Field(help_text='pg Up set')
acting =serializers.Field(help_text='pg Acting set')
up_primary =serializers.IntegerField(help_text='pg up Primary')
acting_primary =serializers.IntegerField(help_text='pg Acting Primary')
この部分は必要ありません。一部のモジュールにはこの部分の操作がない場合があります。前の 3 つの手順で、Rest-API 部分の拡張は基本的に実装されましたが、その中で主要な拡張は ViewSet でした。関連する ViewSet は、実際に cthulhu とrest-api の間の対話メソッドを実装します。
ViewSet の拡張では、rpc は実際にバックグラウンドと対話するために使用されるため、cthulhu の実装部分は主に対応する rpc リクエストを処理します。
rpc.py は、要求されたすべての操作を実装しますが、新しい拡張操作も拡張機能をサポートする必要があります。例として pg を使用して説明を続けます。
defapply(self, fs_id, object_type, object_id, command ) :
"""
クラスター内のオブジェクトを変更しないコマンドを適用します。
"""
cluster = self._fs_resolve(fs_id)
ifobject_type == OSD:
#不明な場合に例外をスローすることを解決します
self._osd_resolve(cluster, object_id)
return cluster.request_apply(OSD, object_id, command)
elifobject_type == PG:
return cluster.request_apply(PG, object_id, command)
else:
raise NotImplementedError(object_type)
そして Pg のリストは Pgsummary を通じて取得されます。この部分は以前の実装ですでに存在していました。前のコードは次のように実装されました:
defget_sync_object(self, fs_id, object_type, path=None):
"""
ClusterMonitor がコピーを保持するオブジェクトを取得します。クラスターマップなどの mon。
:param fs_id: クラスターの fsid
:param object_type: 文字列、SYNC_OBJECT_TYPES の 1 つ
:param path: リスト、オプション、オブジェクト内のパス全体の代わりに返す
:return: 要求されたデータ、または見つからなかった場合は None (``path``
の要素が見つからなかった場合を含む)
"""
ifpath:
obj = self._fs_resolve(fs_id).get_sync_object(SYNC_OBJECT_STR_TYPE[object_type])
try:
パス内の一部の場合:
if isinstance(obj, dict):
obj = obj[part]
else:
obj = getattr(obj, part)
以外 (AttributeError, KeyError) as e:
log.Exception("%s をトラバースする例外 %s: obj=%s" % (e, path,obj ))
raise NotFound(object_type, path)
return obj
else:
returnself._fs_resolve(fs_id).get_sync_object_data(SYNC_OBJECT_STR_TYPE[object_type])
1.4cluster_monitor.py 拡張機能
def__init__(self、fsid、cluster_name、notifier、persister、servers、eventer、requests):
super(ClusterMonitor, self).__init__()
self.fsid = fsid
self.name = クラスター名
self.update_time = datetime.datetime.utcnow().replace(tzinfo=utc)
self._notifier = notifier
self._persister=persister
self._servers =servers
self._eventer =eventer
self._requests =requests
#リクエストの実行に現在使用しているモン、
#ミニオンIDで識別
self._favorite_mon = None
self._last_heartbeat = {}
self._complete = gevent.event.Event()
self.done = gevent.event.Event()
self._sync_objects = SyncObjects(self.name)
self._request_factories = {
CRUSH_MAP: CrushRequestFactory,
CRUSH_NODE: CrushNodeRequestFactory、
OSD: OsdRequestFactory、
POOL: PoolRequestFactory、
CACHETIER: CacheTierRequestFactory、
PG: PgRequestFactory、
ERASURE_PROFILE: プロファイルRequestFactory,
ASYNC_COMMAND: AsyncComRequestFactory
}
自身。 _plugin_monitor = PluginMonitor(servers)
self._ready = gevent.event.Event()
この部分は主に、適切なリクエストを生成できるように、対応するリクエストを対応するリクエスト ファクトリ クラスにバインドすることです。
このファクトリ クラスは主に、さまざまなニーズに合わせて特定のインターフェイス クラスを実装するように設計されています。Pg を例に挙げます。
from cthulhu.manager.request_factory importRequestFactory
from cthulhu.manager .user_request importRadosRequest
from calamari_common.types importPG_IMPLEMENTED_COMMANDS, Pgsummary
class PgRequestFactory(RequestFactory):
def scrub(self,pg_id):
return RadosRequest(
" b on {cluster_name}- pg{id }".format(cluster_name=self._cluster_monitor.name,id=pg_id),
self._cluster_monitor.fsid,
self._cluster_monitor.name,
[('pg スクラブ', {'pgid' : pg_id} )])
defdeep_scrub(self, pg_id):
return RadosRequest(
"{cluster_name}-osd.{id} でディープ スクラブを開始しています。".format(cluster_name=self._cluster_monitor.name ,id= pg_id),
self._cluster_monitor.fsid,
self._cluster_monitor.name,
[('pg deep-scrub', {'pgid': pg_id})])
defrepair(self , pg_id) :
return RadosRequest(
"{cluster_name}-osd.{id} の修復を開始しています".format(cluster_name=self._cluster_monitor.name,id=pg_id),
self._cluster_monitor.fsid,
self. _cluster_monitor.name,
[('pg Repair', {'pgid': pg_id})])
defget_valid_commands(self, pg_id):
ret_val = {}
file('/tmp /pgsummary. txt', 'a+').write(Pgsummary.str + 'n')
pg_summary = self._cluster_monitor.get_sync_object(Pgsummary)
pg_pools = pg_summary['pg_pools']['by_pool']
pool_id = int (pg_id.split('.')[0])
pool= pg_pools[pool_id]
forpg in pool:
if pg['pgid'] == pg_id:
ret_val[pg_id ] = { 'valid_commands': PG_IMPLEMENTED_COMMANDS}
else:
ret_val[pg_id] = {'valid_commands': []}
return ret_val
このクラスは 3 つの異なるコマンドの実装を実装します。コマンドは主にそれに応じてカプセル化されます。これらのキーワードは、ceph ソース コード内のパラメーターに基づいて選択する必要があるため、コーディングの際は、ceph ソース コード内の対応するコマンドの json パラメーター名を参照する必要があります。