インストール
Java 17 以降で、JDK 自身の java.net.http(HTTP と WebSocket)の上で動きます。依存関係もフレームワークもありません。呼び出しはブロックし、エラーは GlacException(非検査例外)をスローし、返されるオブジェクトはレコードで、オプションはメソッドチェーンの …Options、期間は Duration、時刻は Instant です。Maven Central に ai.glac:glac として公開されており、パッケージは ai.glac です。
<dependency>
<groupId>ai.glac</groupId>
<artifactId>glac</artifactId>
<version>0.1.0</version>
</dependency>クライアント
Glac glac = new Glac(); // GLAC_API_KEY and GLAC_API_URL; or Glac.builder().apiKey(key).baseUrl(address).build()
App app = glac.cube().deploy("ghcr.io/acme/api:1.4", new AppOptions().name("api").port(8080)); // Cube: waits until it serves
System.out.println(app.url());
Sandbox sbx = glac.sandboxes().create(); // Sandbox: stays until deleted
Result res = sbx.run("python3 -c 'print(6*7)'"); // res.stdout(), res.stderr(), res.exitCode()
System.out.println(res.stdout() + " " + sbx.url(3000));
Drive drive = glac.drives().create(new DriveOptions().name("data").sizeBytes(10L << 30)); // Drive
System.out.print(Sandbox.runOnce("echo hello").stdout()); // the shorthand: a sandbox for one command, on the default clientglac.cube().deploy は glac deploy と同じです。api という名前のアプリ(なければ先に作成)に新しいバージョンを作り、それがアプリのトラフィックを受け取るまで待ちます。最後の行は唯一の短縮形で、サンドボックスの SDK にある、クライアントなしの 1 行の書き方です。使い捨てのサンドボックスと、自分で呼ぶ delete() 以外に、何かを削除するものはありません。サンドボックスは残しておくものなので、Sandbox は AutoCloseable を実装していません。
new Glac() は、キーを GLAC_API_KEY から、アドレスを GLAC_API_URL(デフォルトは https://api.glac.ai)から読みます。別のアドレス、キー、タイムアウトを使うには、クライアントをビルドします。
Glac glac = Glac.builder().apiKey(key).baseUrl(address).build();
Sandbox named = glac.sandboxes().create(new CreateOptions().name(name).env("STAGE", "dev").neverSleep());| 呼び出し | 内容 |
|---|---|
new Glac(), Glac.builder(): apiKey, baseUrl, timeout, connectTimeout, retries, onResponse |
アドレス、キー、タイムアウト、再試行。1 つのクライアントを、いくつのスレッドで共有してもかまわない |
Glac.shared() |
短縮形が使うクライアント。new Glac() と同じく、最初に使うときに環境変数から作られる |
glac.cube() |
キューブ:アプリ(後述)。glac.workers() はその別名で、@Deprecated が付いている |
glac.sandboxes(), .snapshots(), .sshKeys() |
サンドボックス、そのスナップショット、それを開く SSH キー(後述) |
glac.drives(), glac.volumes(), glac.backups() |
ドライブとそのスナップショット、その下にあるボリューム、ボリュームのバックアップ(ドライブとバックアップはコントロールプレーンの機能。後述) |
glac.domains() |
プロジェクトの独自ドメイン。コントロールプレーンの機能(後述) |
glac.webhooks(), glac.keys() |
プロジェクトのイベントの送信先と API キー。コントロールプレーンの機能(後述) |
glac.destinations() |
プロジェクトのアプリのログ、メトリクス、トレースのエクスポート先。コントロールプレーンの機能(後述) |
glac.secrets(), glac.variables() |
プロジェクトのシークレットと共有変数(後述) |
glac.deploys() |
プロジェクトのデプロイ(/v1/deploys、コントロールプレーンの機能):複数のサービスを、それぞれが待つものの順にまとめてデプロイし、まとめて切り替える(プロジェクトのデプロイ)。create(Map.of("api", new DeployOptions().image("ghcr.io/acme/api:2"), "web", new DeployOptions())) は、各サービスに単独でのデプロイと同じものを渡して待ち(Deploy.await())、置き換わったデプロイがあればそれを追う。失敗すると、デプロイのコード(job_failed、job_timed_out、job_lost など)と、param()(services.<name>)としてのサービスを持つ、型が deploy_failed の GlacException をスローする。create(services, new ProjectDeployOptions().noWait())、get(id)、list() |
glac.account(), updateAccount, usage, usageReport, billing, updateBilling, balance, updateBalance, topUp(usd), charges, ledger, project, events |
どの製品にも属さない、プラットフォーム自体の呼び出し(後述) |
glac.request("GET", "/v1/webhooks", null, null) |
SDK がラップしていない API。レスポンスの JSON を返す |
名前空間は、Glac が作るオブジェクトを返すメソッドで、クライアントごとに 1 つです。オブジェクトには API の名前を使います。キューブは App(API ではアプリ)で、ほかに Sandbox、Drive、DriveSnapshot、Volume、Backup、Domain、Snapshot、SshKey、Secret、Variable、Version、Instance、Deploy があります。
キューブ
キューブ(API ではアプリ)は、固有のアドレスでサービスとして動くイメージで、インスタンスはリクエストに必要なだけ動き、リクエストがなければ 1 つもありません。デプロイのたびにバージョンが作られ、準備ができた時点でアプリのトラフィックを受け取ります。アプリはコントロールプレーンの機能で、単独で動くノードに対しては、どの呼び出しもノード自身の 404 no_such_route になります。
| 呼び出し | 内容 |
|---|---|
glac.cube().deploy(image), deploy(image, new AppOptions().name("api")…) |
glac deploy と同じ。プロジェクトにその名前のアプリがない場合は、指定したすべてのオプションでアプリが作られ、最初のバージョンも一緒に作られる。アプリがある場合は、すぐに反映されるもので指定したもの(リージョン、スケール、キー、エグレス、ログ、トレースなど)を先に変更し(PATCH。指定がある場合のみ)、次に指定したものと、指定しなかったものについてはアプリのものからバージョンを作る(POST …/versions)。その間に誰かが取った名前(409 name_taken)では、その人のアプリへのデプロイになる。名前を指定しなければ、API が名前を付ける新しいアプリになる。noWait() でなければバージョンを待ち、読み直したアプリを返す(url()、currentVersion()) |
glac.cube().create(AppOptions), get(idOrName), getOrCreate(name, AppOptions), list() |
アプリを作成する(イメージを指定すると、最初のバージョンを待つ)。1 つを取得する。取得または作成する(既存のものはそのまま返す)。一覧。drives(List.of(new DriveMount(…))) は、唯一のインスタンスが読み書き可能でマウントするドライブ(多数のインスタンスやキーを持つアプリは 409 drive_single_writer で拒否される。スナップショットの読み取り専用のマウントはサンドボックス用なので、スナップショットを指定したマウントはそこでは 400 unknown_field で拒否される)。keyDrives(List.of(App.KeyDrive.of(name, path))) は、キーを使うアプリのキーごとのインスタンスに専用のドライブを持たせる。ドライブは最初のインスタンスとともに作られ、キーとともに削除される |
glac.cube().logs(idOrName, LogsOptions) |
アプリを取得せずに、ID か名前でアプリのログを読む |
app.deploy(new DeployOptions().image(…)), app.update(AppChanges), app.rollback("1"), app.versions(), app.delete() |
手元のアプリのバージョン。変更。トラフィックをあるバージョンに戻す。バージョンの一覧。削除 |
AppOptions と DeployOptions の .runtime(Map.of("ulimits", Map.of("nofile", 65535))) |
API が受け付けるとおりのバージョンのランタイム設定:ulimits、sysctls、tmpfs、dns、shm_size_bytes。全体が置き換わる |
app.logs(new LogsOptions().follow()), app.logUsage(…), app.deleteLogs(before), app.info().logsState() |
ログ(接続が切れても、コントロールプレーンが再起動しても続く Iterable<LogLine>)。ログが数えた量。行の削除。ログを保持する各マシンが、今そこで出力されるものを長期保存しているかどうか(ログ) |
app.instance(key, region), app.getInstance(key), app.instances(), app.deleteInstance(key) |
キー別インスタンス:キーごとに 1 つのインスタンスを作成、または復帰させる |
instance.upgrade("3"), app.upgradeInstance(key, version); upgrade.await(), await(limit); instance.upgrades(), app.instanceUpgrades(key), app.instanceUpgrade(key, id) |
キーのインスタンスを、アプリの別のバージョンへその場で移す。null はアプリの現在のバージョンで、それ以外は ID か番号(準備ができたもので、古いものも可)。ID、ノード、キー、アドレス、トークン、専用のドライブはそのままで、ディスク、マシン、プロセスが新しいバージョンのものになり、切り替えの間、リクエストはエッジで保留される。進行中の Upgrade を返す(その info():status は preparing、switching、done、failed。fromVersion、toVersion、timings、error、putBack、kind(upgrade または revert)、when、keepDays、rollback(リバートに必要なもの。keepDays の間保持される)、reverts、batch。API でインスタンスのスリープを待つよう求めたアップグレードは、スリープするまで waiting で、取り消された場合(API の DELETE、またはバッチの停止)は cancelled。取り消されたアップグレードは終了しており、その待機は失敗したものと同じく、コード cancelled で例外になる)。すでにそのバージョンなら null を返す。await() は、新しいバージョンが立ち上がらなかった場合、インスタンスを元のバージョンのままにして、型が upgrade_failed の GlacException(コードは upgrade_failed か upgrade_not_here)をスローする |
app.upgradeInstanceWith(key, new UpgradeOptions().version("4").whenAsleep().keepDays(14)), instance.upgradeWith(…) |
whenAsleep(インスタンスがスリープするまで waiting で待ち、スリープした時点で始めるため、リクエストは 1 つも保留されない)と keepDays(0〜365 日、指定しなければ 7 日。完了後にリバートに必要なものを保持する日数で、スナップショットと同じく課金される)を指定した同じ呼び出し。インスタンスとは別のドライブやボリュームをサービスがマウントするバージョンは、その場でのアップグレードにはならず、upgrade_not_here で failed になる |
upgrade.cancel(), app.cancelInstanceUpgrade(key, id); upgrade.revert(), upgrade.revert(keepDays), app.revertInstanceUpgrade(key, id, keepDays) |
待機中(インスタンスのスリープ待ち、またはバッチ内の順番待ち)のアップグレードを取り消す:cancelled になり、インスタンスは元のバージョンのまま(始まったものは 409 upgrade_started)。リバート:アップグレードが保持していたもの(ディスク、アップグレード前の状態のドライブ(先に現在の中身のスナップショットを作る)、移行元のバージョン)にインスタンスを戻す。種類が revert の新しい Upgrade で、アップグレードと同じように進み、待てる。戻り先がもう保持されていなければ 409 rollback_gone で拒否される |
app.upgradeInstances(new UpgradeBatchOptions().version("4").fromVersions(List.of("3")).keys(List.of("k")).whenNow().keepDays(1).concurrency(8).maxFailures(1)); app.upgradeBatches(), app.upgradeBatch(id), app.stopUpgradeBatch(id); batch.await(), await(limit), batch.refresh(), batch.stop() |
アプリの複数のキーを 1 つのバージョン(指定しなければアプリの現在のバージョン)へまとめてアップグレードするバッチ。それぞれインスタンスがスリープした時点で(whenNow なら順番が来た時点で)、指定しなければ同時に 4 つ(1 つのノードでは 2 つ)ずつ行い、指定しなければ 5 回失敗した時点で failed として止まる。info() が UpgradeBatch.Info の UpgradeBatch:status(running、done、failed、stopped)、stopReason、counts、upgrades(各メンバーのキー、アップグレード、ステータス、エラー)、skipped、origin。await() はどう終わってもそれを返す。スリープしないインスタンスのメンバーがあるとバッチは動き続けるため、await(limit) は wait_timeout をスローする。stop() は待機中のメンバーを取り消す |
app.openInstancePort(key, "tcp", port, "2001:db8::/32"), app.instancePorts(key, "tcp"), app.closeInstancePort(key, "tcp", port) |
インスタンスがどこにあっても、キーのインスタンスが持つ専用のパブリック IPv6 アドレスで開いているポート:そのサンドボックスの openPort、ports、closePort を、アプリとキーで指定(UDP なら "udp"。キー別インスタンス)。専用のアドレスのないインスタンスは拒否される(409 no_ipv6) |
AppOptions と AppChanges の checkpoint(n)、AppChanges.noCheckpoint() |
アプリのキー別インスタンスの稼働中に n 秒ごとに取るチェックポイント(1〜600。0 ならデフォルトの 10 秒ごと)と、その解除。App.Info.checkpoint() が設定を示す。インスタンスの SandboxInfo.checkpoint()(SandboxInfo.Checkpoint:everySeconds、lastAt、behindSeconds、bytesPerSecond、storedBytes、error。なければ null)が、チェックポイントの状況を示す |
app.metrics(from, to, step) |
アプリを処理するマシンが計測した値。1 分ごと("hour" なら 1 時間ごと。null なら直近 1 時間を 1 分ごと):ステータスのクラス別のリクエスト、所要時間、インスタンスとその使用量(メトリクス)。API のオブジェクトを返す |
AppOptions と AppChanges の traceSampleRate(0.1)、trustIncomingTrace(true)。app.info().traces() |
アプリのリクエストの一定割合について作られるプラットフォームのスパンで、インスタンス自身のスパンはその子になる(指定しなければなし)。"traces" を受け付けるプロジェクトのエクスポート先に送られる(トレース)。アプリの設定(App.TraceSettings) |
app.createKeySecret(), app.keySecrets(), app.keySecret(id), app.deleteKeySecret(id), KeySecret.signKey(secret, appId, key, expiresAt) |
アプリのキーの署名に使うシークレット(KeySecret。secret() を持つのは作成直後のものだけ)と、それで署名した、エッジを通るリクエストが運ぶ形のキー(署名付きキー)。KeySecret.pathSegment は、それをパスのセグメントとして書く |
立ち上がらなかったバージョンは、type() が deploy_failed で、バージョン自身のコードと出力を持つ GlacException をスローします。トラフィックは元のままです。バージョンを構成するもの(image、startCommand、port、env、secret、vcpus、memoryBytes、volumes、drives、keyDrives など)は DeployOptions のすべてで、アプリが持つそれ以外のものはすぐに反映され、バージョンは作られません。
サンドボックス
| 呼び出し | 内容 |
|---|---|
glac.sandboxes().create(new CreateOptions().image(…).name(…).env(k, v).drive(new DriveMount("/data", id)).sleepAfter(d).neverSleep().sleepNotice(d).sleepHoldMax(d).egress(…)) |
サンドボックスを作成する。どのオプションも省略可能。起動時に始めるサービス:start(true)(イメージ自身の起動コマンド)、startLine(…)、startArgv(…) を、readyTcp(port)、readyHttp(port, path)、readyCommand(…) とともに指定。hostname(…)、stopSignal(…)、stopGrace(d)。projectNetwork() で最初からプロジェクトのプライベートネットワークにつなぐ(info().projectAddress())。new VolumeMount("/data", vol).withCopy() は、イメージのそのパスにあるものを新しいボリュームに入れる(サンドボックスの作成) |
sbx.info().appId(), versionId(), key(), imageDigest() |
コントロールプレーンで作ったサンドボックスはアプリのインスタンスである。イメージを指定せずに作った場合はプロジェクトのデフォルトのサンドボックスアプリ(sbx-sandbox)、それ以外はそのイメージのアプリ(アプリの instances() は、そのアプリのサンドボックスをそれぞれのキーの下に一覧表示する)。サンドボックスが属するそのアプリのバージョン、作成元のイメージ(その後移動したタグはアプリの新しいバージョンになり、それ以降に作ったサンドボックスはそちらに属する)、そこでのキー、名前または ID、ダイジェストで示すイメージ。作成のレスポンスとすべての読み取りで示され、保持される。テンプレートやスナップショットから作ったものと、フォークでは null |
glac.sandboxes().get, getOrCreate, list(ListOptions), listPage(ListOptions) |
検索。検索または作成。一覧(すべて、または 1 ページ分) |
CreateOptions と UpdateOptions の suspendAfter(d)、wakeDailyAt("03:30")(defaultSuspendAfter()、noDailyWake() で元に戻す)。SandboxInfo.suspendAfter()、wakeDailyAt() |
アイドルで停止した後、メモリを保存して本当にスリープするまで一時停止したままでいる時間(1 秒〜1 日。ノードは最大 10 分に抑える)と、休止中に、復帰を待つ自身の処理のために毎日復帰させる時刻(UTC) |
CreateOptions と UpdateOptions の onExpiry("sleep")、heldAsleep(true)。SandboxInfo.onExpiry()、heldAsleep() |
expiresAt の時刻が来たときの動作:サンドボックスを delete(デフォルト)、sleep(スリープさせて保持し、リクエストではいつもどおり復帰)、hold(同じく、スリープのまま保持)。そしてスリープ中にポートへのリクエストで復帰させるかどうか。スリープのまま保持されている間、プレビューアドレスは 502 sandbox_paused を返し、API の呼び出しでは復帰する |
glac.sandboxes().run(command), run(command, RunOptions, CreateOptions) |
1 つのコマンドのためのサンドボックス:作成、実行、削除 |
CreateOptions.init("systemd"); SandboxInfo.init() |
システム全体:イメージ自身の systemd がサンドボックスの PID 1 になる(イメージを指定しなければ、systemd と OpenSSH 入りのプラットフォームの Ubuntu)。パッケージ、systemctl で起動するサービス、cron、ジャーナルが通常のマシンと同じように動き、専用のマシン ID を持ち、スリープ、復帰、移動を経ても保たれる。起動コマンドや準備完了のチェックとは併用できず(400 invalid_start)、スナップショットからも作れない。init() は、systemd なら "systemd"、プラットフォームの init なら null |
sbx.run(command, new RunOptions().cwd(…).timeout(d).onStdout(…)) |
実行して待つ。Result は stdout、stderr、exitCode、duration、usage、wake を持つ |
sbx.exec, sbx.terminal() |
コマンドを開始する(waitFor()、output()、write()、kill())。ターミナル |
sbx.files() |
read、readText、open、write、list、stat、exists、mkdir、move、remove、そして setAttributes(path, mode, sizeBytes, modifiedAt):ファイルのモード、長さ、最終更新時刻(null ならそのまま)。.asUser("node") |
sbx.url(port), sbx.token(scopes, expiresIn) |
ポートへのリンク(ローカルで署名)。このサンドボックス用のトークン |
sbx.info().ipv6(), sbx.openPort("tcp", port, from…), sbx.ports("tcp"), sbx.closePort("tcp", port), inbound(InboundPort.tcp(port, from…)) |
専用のパブリック IPv6 アドレス(ある場合。なければ null)。指定した送信元(IPv6 のプレフィックスかアドレス。全員なら "::/0")に対して開いたポートと、その接続先。開いているポートの一覧。ポートを閉じる(開いていたかどうかを返す)。CreateOptions と UpdateOptions の一覧。受信はデフォルトで閉じており、開いたものはスリープ中も移動しても開いたまま。ネットワークを参照 |
sbx.revokeToken(token) |
そのトークンだけがそれ以降拒否され、ほかのトークンはそれまでどおり使える。Token(その id() である tok_… で特定される)、トークンそのもの、またはその ID で指定。1 つのサンドボックスで保持できる、期限の切れていない個別の無効化は 1,000 個まで(超えると 409 too_many_revoked_tokens。その場合は revokeTokens() を使う)。tokenId() と expiresAt() を持つ TokenRevocation を返す |
sbx.revokeTokens() |
それまでにこのサンドボックス用に発行したトークンがすべて使えなくなる(401 invalid_token)。プレビューリンクや Cookie の中のトークン、SSH セッションが持つトークンも含む。その後に作ったトークンは使える。API キーが必要。TokenRevocation(sandboxId()、generation()、revokedAt())を返す |
sbx.update, sbx.sleep(), sbx.restart(), sbx.delete(), sbx.snapshot(), sbx.fork(n), sbx.restore(…) |
変更。スリープ。ディスクからの起動。削除。スナップショット。フォーク。復元 |
new CreateOptions().checkpoint(10), new UpdateOptions().checkpoint(10), .noCheckpoint(); info().checkpoint() |
稼働中のチェックポイント(1〜600 秒間隔)。マシンが失われてもプロセスごと再開できる。解除。状況。チェックポイントを取れるマシンがなければ 409 checkpoints_unavailable |
info().diskWrites() |
今日(UTC の 1 日)のディスクの書き込み量と、全速で書き込める 1 日の割り当て量(SandboxInfo.DiskWrites):todayBytes()(うちチェックポイントのコピーがホストのディスクに書き込んだ量が checkpointCopyBytes())、fullSpeedUntilBytes()(割り当て量。ノードに別の指定がなければ 100 GiB。null ならノードは何も減速しないが、数えることは同じ)、limited() と limitedUntil()(割り当てを超えると、その日が終わるまでディスクは毎秒 2 MiB で書き込みを受け付け、失敗する書き込みはない)。ディスクをオブジェクトストアにコピーしないノードでは null で、何も数えない。ドライブへの書き込みはここでは数えない(ドライブへの書き込みに料金はかからない) |
glac.sandboxes().snapshots(): get, list; snap.rename(name), snap.expireAt(at) |
スナップショット:ある瞬間のメモリ、プロセス、ディスク。別の名前(null ならなし)、または自動で削除される時刻(null なら削除しない) |
glac.sandboxes().sshKeys(): create(publicKey, SshKeyOptions), get, list |
SSH ゲートウェイを通じてサンドボックスを開く公開鍵。秘密鍵は、何かを送る前に拒否される |
短縮形。Sandbox.runOnce、Sandbox.create、Sandbox.get、Sandbox.getOrCreate、Sandbox.list、Sandbox.listPage は、Glac.shared().sandboxes() の呼び出しで、実装は 1 つです。クライアントなしの static メソッドを持つ製品はほかにありません。使い捨ての実行は、名前空間では run、クラスでは runOnce です。Java では同じシグネチャの static メソッドとインスタンスメソッドを持てないためです(sbx.run はサンドボックスでコマンドを実行します)。コマンドを待つのは waitFor です(wait() は Object のものです)。String で指定したコマンドは sh -c で実行され、List<String> ならプログラムとその引数です。
Command cmd = sbx.exec("node server.js"); // do not wait
try (Output out = cmd.output()) {
for (Piece piece : out) {
System.out.print(piece.text());
}
}ドライブ
ドライブは、サンドボックスより長く残るプロジェクトのディスクです。サンドボックスの作成時か実行中に、一度に 1 つのサンドボックスが読み書き可能でマウントし、サンドボックスがなくなると中身ごと保持され、次のサンドボックスがマウントできます。次のサンドボックスは同じリージョンのもの、またはマシンがホームのオブジェクトストアを読める別のリージョンのもの(後述)です。書き込まれるそばからリージョンのオブジェクトストアにコピーされるため、別のノード上のサンドボックスもマウントできます。その場合は先にそこへ運ばれます。課金されるのは書き込まれたものだけです(usedBytes)。スナップショットはそのストア内のドライブのバージョンで、そのために何もコピーされません。フォークはスナップショットから作る新しいドライブ、復元はドライブをスナップショットの状態に戻すもので、いくつものサンドボックスがスナップショットを同時に読み取り専用でマウントできます(後述)。ドライブはコントロールプレーンの機能で(/v1/drives)、単独で動くノードに対しては、どの呼び出しもノードの 404 no_such_route をスローし、そのノードのディスクはボリュームです(後述)。
Drive data = glac.drives().create(new DriveOptions().name(name).sizeBytes(1L << 30));
Sandbox with = glac.sandboxes().create(new CreateOptions().drive(new DriveMount("/data", data.id())));
with.run("echo kept > /data/note");
glac.drives().detach(with.id(), data.id());
Sandbox other = glac.sandboxes().create();
glac.drives().attach(other.id(), new DriveMount("/data", data.id()));
System.out.println(other.run("cat /data/note").stdout()); // kept| 呼び出し | 内容 |
|---|---|
glac.drives().create(new DriveOptions().name(…).sizeBytes(…).region(…).durability(…)), get(idOrName), list(), listPage(ListOptions) |
ファイルシステム以外は空のドライブを作る。どのオプションも省略可能(sizeBytes:4 KiB ブロックの整数倍で最小 16 MiB。指定しなければ 64 GiB、無料プランでは 5 GiB。region:na、eu、ap。durability:standard、またはゲストの fsync が、それ以前のすべての書き込みがオブジェクトストアに届いてから戻る strict)。1 つを取得。新しい順の一覧。1 ページ分 |
glac.drives().rename(drive, name), glac.drives().delete(drive) |
名前の変更(null なら名前なし)。中身ごと削除 |
glac.drives().attach(sandbox, new DriveMount(path, drive)), detach(sandbox, drive), forceDetach(sandbox, drive) |
既存のサンドボックスに、読み書き可能ですぐにマウントする(スリープ中のサンドボックスは復帰する)。アンマウントする(プロセスが使っている間は forceDetach)。どれもドライブを返す |
drive.attach(sandbox, path), drive.detach(sandbox), drive.rename(name), drive.refresh(), drive.delete() |
同じことを Drive に対して行う。その info() は Drive.Info:id(vol-…。ドライブはボリュームでもある)、name、sizeBytes、usedBytes、attachedTo(Drive.Attachment:サンドボックス、パス、モード)、region、home、status、lease(Drive.Lease:唯一の書き込み元のノード、エポック、期限)、appId と key(キー別インスタンスのもの)、parentDriveId と rootDriveId(フォークの場合:フォーク元のドライブ(その後削除されている場合もある)と系統の最初のドライブ。フォークでないドライブでは null)、managedBy(ManagedBy。そのドライブを持つデータベースの id。それ以外では null)、createdAt。データベースのドライブを読み書き可能でマウントできるのはデータベースのインスタンスだけで、名前の変更、復元、削除はデータベースを通じて行う。ここでのそれらの呼び出しは拒否される(409 managed_by_database)。そのスナップショットとフォークはプロジェクトで取得できる。データベースを構成するアプリも同じように示し(app.info().managedBy())、その更新、デプロイ、ロールバック、削除も同じく拒否される |
glac.drives().snapshot(drive), snapshot(drive, new DriveSnapshotOptions().name(…).fsConsistent()), drive.snapshot() |
ドライブのスナップショットを取り、DriveSnapshot を返す。オブジェクトストア内に保持されるドライブのバージョンで、何もコピーされない。実行中のサンドボックスが読み書き可能で持っているドライブは、ゲストの書き込みを短時間(最大 10 秒。超えると再試行可能な 503 unavailable)止めて取る。fsConsistent() を指定すると、サンドボックスのエージェントがファイルシステムを凍結する(consistency は frozen。エージェントが凍結できなければ 409 not_frozen なので、指定せずに取る)。指定しなければマシンを一時停止する(paused。停電時と同じ状態)。実行中のサンドボックスが持っていないドライブは at_rest。ノードがオブジェクトストアに何もコピーしないドライブにはスナップショットはない(409 not_copied) |
glac.drives().snapshots(drive), allSnapshots(driveDeleted), getSnapshot(drive, snapshot), deleteSnapshot(drive, snapshot), drive.snapshots() |
ドライブのスナップショットの一覧(新しい順)。プロジェクトの全ドライブのスナップショット(true ならその後削除されたドライブのものだけ。null ならすべて)。ID で指定した 1 つ(404 snapshot_not_found)。1 つの削除 |
glac.drives().fork(drive, new ForkOptions().name(…).fromSnapshot(snapshot)), drive.fork(…), snap.fork(name) |
スナップショット、またはドライブの現在の状態を最初のバージョンとする新しいドライブ。何もコピーされず、すぐにマウントできる。その parentDriveId と rootDriveId が作成元を示す。作成と同じく、プランのドライブ数の上限の対象(403 drive_limit_reached) |
glac.drives().restore(drive, snapshot), drive.restore(snapshot), snap.restore() |
ドライブの最新のバージョンの後に、スナップショットの内容を持つ新しいバージョンを作る。その間のバージョンは、スナップショットかフォークが保持している限り残るため、古いスナップショットに復元した後に新しいスナップショットに復元することもできる。サンドボックスが読み書き可能で持っているドライブは拒否される(409 drive_attached)。先にデタッチする |
new DriveOptions().historySeconds(n), glac.drives().setHistory(drive, n), versions(drive), versionAt(drive, t), new ForkOptions().at(t), restoreTo(drive, t); drive.setHistory, drive.versions(), drive.restoreTo(t) |
ドライブのバージョンのウィンドウ(slice DB8):時刻を指定して、どこまで遡って復元またはフォークできるか。3600〜86400 秒(指定しなければなし。オフにすると、保持していたものは消える)。書き込みがあった 30 秒ごとに、ある時点のドライブであるバージョンが 1 つウィンドウに加わり、それらが単独で保持するものは、スナップショットと同じく課金される。時刻を指定した復元やフォークでは、その時刻以前の最新のバージョンが使われる。その時刻を指定してバージョンの一覧を呼び出すと、そのバージョンが示される。versions は Drive.WindowVersion を新しい順に返す。setHistory(drive, null) でウィンドウをオフにする。Drive.Info の historySeconds、history |
new DriveOptions().cacheBytes(n), glac.drives().setCache(drive, n); drive.setCache(n), drive.info().cacheBytes(), drive.info().cachedBytes() |
ドライブのキャッシュ:ノードが NVMe に保持するドライブの最大量。指定しなければ全量(ドライブのサイズ)。0 まで減らせ、それを超えた分はオブジェクトストアだけにあり、ゲストが読むとそこから読み取られる(最も長く読まれていないものから手放し、ストアにまだないものは手放さない)。キャッシュは、ドライブが保持するデータとは別に、埋まっている量に応じて 1 時間ごとに課金される。小さくすると、超えた分はストアが保持した時点で手放される(実行中のサンドボックスが全量キャッシュでマウントしたドライブでは、そのサンドボックスが次にスリープまたは停止した時点から)。大きくすると、それ以降にゲストが読んだものを保持する。API ではドライブをボリューム(/v1/volumes)と呼び、クライアントは /v1/drives でアクセスする(以前と同じように応答する)。setCache(drive, null) で再び全量にする。コントロールプレーンがキャッシュについて何も示さない場合、cacheBytes() はドライブのサイズ。cachedBytes() は、現在ノードの NVMe にある量(どのノードも保持していなければ null)。使用量のレポートのグループと合計には cacheGbHours() がある |
glac.drives().attachSnapshot(sandbox, new DriveMount(path, drive).withSnapshot(snapshot)), detachSnapshot(sandbox, snapshot), forceDetachSnapshot(sandbox, snapshot), snap.attach(sandbox, path), snap.detach(sandbox) |
既存のサンドボックスにスナップショットを読み取り専用でマウントする。スナップショットの ID で外す。どちらもスナップショットを返す。サンドボックスの作成時には new CreateOptions().drive(new DriveMount(path, drive).withSnapshot(snapshot))、または new DriveMount(path, snap) |
snap.info(), snap.refresh(), snap.delete() |
DriveSnapshot.Info:id(dsnap-…)、driveId、name、consistency、usedBytes(取得時にドライブが保持していた量)、exclusiveBytes(単独で保持する量)、exclusiveAt、version、createdAt |
- ドライブは一度に 1 つのサンドボックスのものです。ほかのサンドボックスが持っているドライブは拒否され(409
drive_attached)、アタッチ中のドライブの削除も拒否されます。キー別インスタンスのドライブは、キーとともに削除されます(409key_drive)。 - 別のノードが保持しているドライブは、先にサンドボックスのノードへ運ばれます。オブジェクトストアがまだ現在の状態を保持していない間(503
copy_behind)や、運べなかった場合(503drive_not_brought)、呼び出しは再試行可能です。クライアントはretriesの指定どおりに再試行し、それでも失敗すれば例外をスローするので、少し後に再度要求してください。 - リージョンをまたぐ場合(slice D9)。ドライブのホーム(
home)とは、そのコピーを保持するオブジェクトストアのリージョンで、作成されたリージョンです。別のリージョンのサンドボックスも、そのリージョンのマシンがホームのストアを読める場合はマウントできます(読めなければ 409not_on_one_machine)。ドライブはバージョンとして手放され、そこで引き継がれ、ゲストが読むのに合わせてホームのストアから読み取られ、ゲストが書き込むものは今いるリージョンのストアに送られます(region)。ホームは、そこに 1 時間いると追従します。glac.drives().moveHome(drive)(drive.moveHome())を使えばすぐに移ります。マシンがホームのストアに残っているものを自分のストアにコピーし、何も残らなくなった時点でhomeが新しいリージョンになります。Drive.Info#homeMoveが移動の進み具合を示します(asked_at、asked_by、copied_objects、copied_bytes、objects_left、error)。古いホームのコピーは、保持しているどのバージョンも必要としなくなった時点で消えます(1 日後)。ドライブのホームが移るのは最大で 6 時間に 1 回で(409home_moved_recently)、ホームが現在のリージョンにあるドライブでは 409home_hereになります。 - プランの制限:無料プランでは最大 10 GiB のドライブを 3 つ(合計 15 GiB)、有料プランでは最大 1 TiB のドライブを 500 個です(403
drive_limit_reached)。 new UsageOptions().drive(id)、kind("drive")、groupBy("drive")は、ドライブが保持した量、書き込まれた量、キャッシュ外から読まれた量を報告します。イベントdrive.created、drive.deleted、drive.attached、drive.detachedは、Event.DriveかEvent.DriveAttachedを運びます。- **スナップショットはドライブより長く残ります。**ドライブの削除後も、ドライブの ID で一覧表示、読み取り、フォーク、読み取り専用でのマウントができます。単独で保持する量(
exclusiveBytes)に対して、1 時間ごとに、ドライブのデータの料金(1 GB-月あたり $0.02)で課金されます。 - フォークは、ほかのドライブと同じく、
usedBytes、つまり論理的な内容全体で課金されます。10 GB のスナップショットのフォークは、10 GB のドライブとして課金されます。 - **読み取り専用のマウント。**ドライブのリージョンのどのマシン上でも、ドライブを誰が持っていても、ドライブが削除された後でも、いくつものサンドボックスがスナップショットを同時にマウントできます。ブロックはゲストが読むのに合わせてオブジェクトストアから届きます。このキャッシュ外の読み取りに料金はかからず、使用量ではそのサンドボックスの下に表示されます(
glac.usageReport(new UsageOptions().sandbox(id))のdriveColdReadBytes())。そのサンドボックスのマシンがすでに保持しているものの読み取りにも料金はかかりません。ゲストは書き込めず、それをマウントしたサンドボックスは別のマシンへ移動しません。attachはスナップショットを指定したマウントを、attachSnapshotは指定しないマウントを受け付けず、detachSnapshotはdsnap-…以外の ID を受け付けません。いずれも何かを送る前に拒否されます。
glac.volumes() は API の /v1/volumes で、ドライブの下にあるディスクです。移行のために残されています。これにしかないのは、ディスクがボリュームである単独で動くノードと、複数のサンドボックスが同時にマウントするファイルシステムである共有ボリュームです。コントロールプレーンは、プロジェクトのキーに対して通常のボリュームを作りません。create()、create(VolumeOptions)(name、sizeBytes、shared)、get(idOrName)、list() があり、vol.delete() はどのサンドボックスも持っていないボリュームを削除します(サンドボックスが持っているボリュームは 409 volume_in_use)。サンドボックスは new CreateOptions().volume(new VolumeMount("/team", vol.id())) で、アプリのインスタンスは AppOptions.volumes(…) でマウントします。
**ボリュームのバックアップ。**バックアップは、ある瞬間のボリューム(ドライブもボリュームです)のコピーで、オブジェクトストアに、期限が来るまで保持されます。呼び出しによって、ボリュームのルールに従って毎日、またはサービスの新しいバージョンがインスタンスを置き換える前に取得されます。ドライブのスナップショットと違い、それ自体が独立したコピーで、それだけからボリュームを作ることができ、元のボリュームより長く残ります。ボリュームのバックアップは前回以降に変わったものだけを保持し、複数のバックアップが必要とするブロックは、そのうち最も古いもので 1 回だけ課金されます。ストアがすべてを受け取るまでは making、その後は ready で、それ以降はストアが保持する量(storedBytes)に応じて、スリープ中のサンドボックスが保持するものと同じ料金で課金されます(バックアップ)。バックアップはコントロールプレーンの機能です。
| 呼び出し | 内容 |
|---|---|
glac.volumes().backup(idOrName), backup(idOrName, new BackupOptions().expiresInDays(7)), vol.backup(), glac.volumes().backups(idOrName) |
今すぐバックアップを取り、Backup を返す。指定した日数(1〜365)、またはボリュームのルールの日数(設定しなければ 30 日)保持される。ボリュームのバックアップの一覧(新しい順。削除済みのボリュームのものは、その ID で)。オブジェクトストアに何もコピーしないノードにはバックアップはない(409 not_copied) |
glac.backups().list(), listOf(volumeId), get(id), delete(id), restore(id, name) |
プロジェクトのバックアップの一覧(新しい順。削除済みのボリュームのものも含む)。1 つのボリュームのもの。1 つの詳細。1 つの削除(それ以降は課金されず、そこから作ったボリュームは残る)。準備ができたバックアップから作る新しいボリューム(name は null でもよい)。glac.volumes().create(new VolumeOptions().fromBackup(id)) と同じ(作成中は 409 backup_not_ready、失敗後は 409 backup_unusable) |
b.refresh(), b.restore(name), b.delete() |
同じことを Backup に対して行う。その info() は Backup.Info:id(bak-…)、volumeId、volumeName(その時点のボリュームの名前)、status(making、ready、failed)、reason(manual、daily、before_version)、consistency(frozen、crash)、frozenMs(ボリュームの書き込み元がコピーのために待った時間。凍結しなかった場合は null)、sizeBytes(ボリュームが保持していた量)、volumeSizeBytes(保持できた最大量。そこから作るボリュームが保持する量)、storedBytes(課金の基準)、ownBytes(削除すると減る量)、sharedBytes、shared、region、failure、createdAt、readyAt(課金の開始時刻)、expiresAt |
- バックアップから作るボリュームは、バックアップ元のボリュームと同じサイズと種類で、バックアップのリージョンに作られます。
info().status()は、バックアップ全体を保持するまではrestoring、その後はreadyで、それまではアタッチできません。fromBackup()がバックアップを示します。配置先のマシンで復元できない場合、コントロールプレーンはリージョンの別のマシンにもう一度作ります。そのときrestoreAttempt()は 2 になり、firstFailure()が最初の試行に失敗した理由を示します。それも失敗するとfailed(failure())になり、削除しかできません。 new UsageOptions().backup(id)、kind("backup")、groupBy("backup")は、バックアップが保持した量を、状態の計測項目(state_gb_hours)で報告します。glac.billing()のmeters().state().backupsGbHours()は、その計測項目のうちバックアップの分を示します。
ドメイン
プロジェクトのドメインは、デフォルトのアドレスと同じくアプリへ、またはサンドボックスのポートへ向かう名前です。ドメインはコントロールプレーンの機能です。
| 呼び出し | 内容 |
|---|---|
glac.domains().create(domain, new DomainOptions().app(…)) または .sandbox(…).port(…)(.proxied(…) を指定可能)。get、list()、list(new ListOptions().app(…))、delete。domain.update(…)、domain.refresh()、domain.delete() |
アプリまたはサンドボックスのポートのための名前。verification が求めるレコードが DNS に現れるまでは pending_verification(独自ドメイン)。プロジェクトにすでにあれば 409 domain_exists |
ブラウザ
**未公開。**Glac のブラウザはまだ利用できません。以下は公開に先立つ、現時点での SDK です。
セッションは Glac がホストする Chromium で、Chrome DevTools Protocol(CDP)のクライアントが外部で操作します。Playwright for Java は playwright.chromium().connectOverCDP(session.cdpUrl()) で接続します。クライアントの接続中は稼働し、最後のクライアントが離れると数秒後に、ページを保持したままスリープします。アドレスには認証情報が含まれるため、toString() はアドレスを含みません。
glac.browsers().create(new BrowserOptions().name("agent-42"))(またはcreate())は稼働中のセッションを作ります。BrowserOptionsには、kind(デフォルトのchromium-headless、画面付きのchromium、またはレイアウトエンジンのないブラウザであるlightpanda)、name、region、sleepAfterSeconds、connectionIdleSeconds、deleteAfterIdleSeconds、metadata、profile(name, save)とprofile(name, version, save)(セッションを返す前に読み込むプロジェクトのプロファイル。saveなら削除時に保存し直す)、proxy(url)(CONNECTを受け付ける自前の HTTP プロキシ。有料プランのみ。セッションのポート 80 と 443 への接続は、ブラウザの隣にあるリレーによってそこを経由して送信され、認証情報はプラットフォームが保持する。無料プランでは 403proxy_not_on_plan)があります。既存のセッションの名前を指定すると、そのセッションがページとともに復帰して返されます。実行前にサンドボックスが失敗したものはセッションにならず、作成は 503session_failedで拒否されます。glac.browsers().get(idOrName)、delete(idOrName)(保存するプロファイルを指定して作ったセッションは、先にプロファイルを保存)、deleteWithoutSavingProfile(idOrName)、そしてセッション自身のdelete()とdeleteWithoutSavingProfile()があります。BrowserSessionは、id()、status()、cdpUrl()、profile()(BrowserSession.Profile:name、save、version)、proxy()(BrowserSession.Proxy:自前のプロキシのurlとusername。パスワードは含まない)、proxyBytes()(プロキシを双方向に通過した量)、そしてinfo()(種類、liveUrl、各種の時刻、awakeSeconds、proxySentBytes、proxyReceivedBytes)を持ちます。status()は、awake、asleep、unavailable(ノードに到達できない)、failed(作成に応答した後でサンドボックスが失敗した。たとえばブラウザが停止して戻らなかった)のいずれかで、失敗した場合はerror()が理由を示します(BrowserSession.Failure:ノードが返したとおりのcode、message。失敗していなければnull)。イベントbrowser.failedもそれを伝え、Event.BrowserFailed.of(event)でそのデータを読みます。
セッションは、ほかのインスタンスと同じく、使用したキューブのリソースで課金されます。処理している間の CPU、稼働中のメモリ、送信トラフィックです(料金とプラン)。session.info().awakeSeconds() は稼働していた時間です。
一覧表示、変更、スリープ、新しいアドレスの発行は、Python と TypeScript の SDK と glac browsers にあります。セッションはコントロールプレーンの機能です。
データベース
データベースはマネージド Postgres です。ドライブ上で動く専用の PostgreSQL で、何も要求がないときはスリープし、接続があればセッションを保ったまま復帰します。オーナーのパスワードは create と resetPassword のレスポンスにしか含まれず、どこにも保存されません。そのどちらかが返した Database の connectionString() には、パスワードが含まれます。
glac.databases().create("shop")、またはcreate("shop", new DatabaseOptions().version("18"))は、データベースを作成し、最初の起動を待ちます(status()はready、またはcreating。その場合は準備ができるまでgetしてください)。DatabaseOptionsには、version、region、databaseName、size(vcpus, memoryBytes)、storage(sizeBytes, durability)、sleepAfterSeconds、suspendAfterSeconds(メモリを保存して本当にスリープするまで一時停止したままでいる時間。その間の接続には 1〜2 ミリ秒で応答する。1〜86400 秒、デフォルトは 300 秒)、wakeDailyAt("03:30")(休止中に毎日その時刻に復帰させる)、metadataがあります。既存のデータベースの名前を指定すると、パスワードなしでそのデータベースが返されます。glac.databases().setSuspendAfter(idOrName, n)とsetWakeDailyAt(idOrName, "04:00")は、この 2 つを全ブランチまとめて変更し、nullでそれぞれ元に戻します(300 と、なし)。無料プランでは、Neon の無料プランがゼロまでスケールするのと同じく、データベースの休止の設定は固定です。最後のクエリの 1 秒後に一時停止し(sleep_after_secondsは 1)、その 5 分後にスリープします(suspend_after_secondsは 300)。ほかの値は、作成でも変更でも 400invalid_fieldで拒否されます。glac.databases().createBranch(idOrName, "preview", parent, expiresAt)は独自のブランチを作ります(parentがnullならmain、expiresAtがnullなら残り続ける)。親の現在の状態を、何もコピーせずに引き継ぎ、プロジェクトのネットワーク上の<database>-<name>に専用の PostgreSQL、エンドポイント、ドライブを持ちます。ロールとパスワードは親のものです(branch.connectionString(ownerPassword))。deleteBranch(idOrName, branch)は PostgreSQL を止めてドライブを削除します。main(409root_branch)や、ほかのブランチの作成元になったブランチ(409has_branches)は削除できません。new DatabaseOptions().historySeconds(n)、glac.databases().setHistory(idOrName, n)、restore(idOrName, t)、restore(idOrName, t, exact)、createBranch(idOrName, name, parent, expiresAt, at)、createBranch(…, at, exact)(DatabaseのhistorySeconds、history):履歴(slice DB8 と DB5)で、時刻を指定して、ルートブランチをどこまで遡って復元できるか、またはブランチを作れるかです。指定しなければ 1 日で、有料プランでは 0(なし)〜30 日、無料プランでは 1 日です。復元はルートブランチをその場で戻します。分ちょうどの時刻やバージョン自体の時点なら、その時刻以前で最新の、ドライブのウィンドウのバージョンへ(書き込みがあった 30 秒ごとに 1 つ、最大 1 日分)。それより前や秒単位の時刻、またはexactを指定した場合は、WAL アーカイブによってその時点そのものへミリ秒単位で戻します(WAL をその時点まで再生します。数秒〜数分かかり、呼び出しは待ちます)。エンドポイント、接続文字列、オーナーのパスワードは変わらず、接続は切断され、復元前の状態は独自のブランチmain_old_<the restore's moment>として保持されます。新しいバージョンが 5 分以内に応答しなければ取り消されます(503database_restore_failed)。時刻を指定したブランチは、代わりにその時点から作られます(from: {at, exact})。履歴にない時刻は 400invalid_historyになり、そのメッセージは、ウィンドウとアーカイブがいつから遡れるかを示します。秒単位の時刻(またはexact)はアーカイブから戻すか拒否され、その前のウィンドウのバージョンが使われることはありません。アーカイブが届かない場合(アーカイブを保持しないデータベース、または最も古いベースより前の時刻)は 400invalid_history、アーカイブのストアがセグメントを拒否している間は 503database_archive_unavailable(再試行可能)です。どの拒否も、その時刻以前のウィンドウのバージョンを示すので、代わりにそのバージョン自体の時点を指定できます。ストアがブロックを返さない場合は 503drive_unreadable(再試行可能)で拒否され、何も作られません。オブジェクトストアの障害が長引き、ドライブがログのために保持できる量を超える WAL が待つことになると、データベースを動かし続けるためにその WAL は手放されます。これがアーカイブの欠落で、history().gaps()(Database.Gap:from、to、fromLsn、toLsn)に示されます。手放した WAL の開始時刻、アーカイブがどの時刻も復元できない期間の終わり(その後に取った最初のベースの終わり。それまでは null)、ログ内での開始位置と終了位置です。欠落の間の時刻は、ドライブのウィンドウからしか復元できず(分ちょうどの時刻、またはバージョン自体の時点)、秒単位や exact では 400invalid_historyになります。欠落はイベントでも伝えられます。最初に見つかったとき(データベースの稼働中に、欠落ごとに 1 回)にdatabase.history_gap、その後アーカイブが再び復元できるようになったときにdatabase.history_resumedです。Event.DatabaseGap.of(event)はそれらのデータを読みます(ほかの種類のイベントなら null)。データベース、欠落のfrom()、to()(前者では null)、fromLsn()とtoLsn()、segments()(手放した 16 MB のセグメントの数)、そして前者ではerror()(オブジェクトストアの最後の拒否の内容)です。new DatabaseOptions().tiering(true)とglac.databases().setTiering(idOrName, on)は、階層型ストレージのオンとオフを切り替えます(slice DB18:有料プランで、オブジェクトゲートウェイが提供されている場合のみ。階層化されたパーティションを持つブランチがある間、オフは 409tiered_data_existsで拒否されます。そのために各ブランチの PostgreSQL が 1 回再起動します)。Databaseのtieringは、オンかどうかと、現在の課金の基準を示します。get(idOrName)、list()、listNamed(name)、delete(idOrName, finalSnapshot)(finalSnapshotが false でなければ、ドライブのスナップショットを 7 日間保持)、branches(idOrName)(最初にmain、次に独自のブランチ)、branch(idOrName, "main")、sleepとwake(ブランチをすぐに)、resetPassword(idOrName, role)(新しいパスワードはこのレスポンスにだけ含まれる。nullはデータベースのオーナー)があります。glac.databases().roles(idOrName)は、ルートブランチのログインするロールを、PostgreSQL 自体から読み取って一覧表示します(DatabaseRole:name、owner)。オーナーと、作成したロール(CREATE ROLE … LOGIN)で、プラットフォームのロールは含みません。resetRolePassword(idOrName, role)は、そのどれかに新しいパスワードを与え、それはこのレスポンスにだけ含まれます。ロールのpasswordと、そのロールでのルートブランチの接続文字列(connectionString())を持つDatabaseRoleSecretです。オーナーの接続文字列は、API が返すデータベースから作られます。独自のブランチは、作成時のパスワードを保持します。db.connectionString()とbranch.connectionString(password):libpq と psql に渡せる URI で、API が返す場合はパブリックなもの、そうでなければプロジェクトのネットワーク上のものを、オーナーのパスワード(パーセントエンコード)入りで返します。DatabaseとDatabaseBranchは API のフィールドのレコードです:defaultBranch()、connectionUri()、pooledUri()、privateUri()、endpoint()、state()。
データベースには、プロジェクトのネットワーク上で、そのサンドボックス(project_network で作成)とサービスから名前でアクセスします。これが private_uri です。エッジが PostgreSQL を提供する場合は、パブリックアドレスでどこからでもアクセスできます(connection_uri、ポート 5432、TLS のみ。プーラーは pooled_uri)。提供するエッジがない場合や、データベースに名前を付けるリージョンがない場合は null で、接続文字列は、それらがあればそれらを使います。toString() は、パスワードも接続文字列も表示しません。データベースはコントロールプレーンの機能です。
マネージドアプリケーション
カタログのアプリケーション(たとえば Rivet)は、プロジェクトに専用のキューブのリソースとしてインストールされます。アプリ、ボリューム、シークレット、バケットで、インストールのラベルが付き、変更はインストールを通じてのみ行い、それぞれのリソースとして課金されます(マネージドアプリケーション)。インストールのレスポンスには、秘密のもの(管理者トークン、それを含むエンドポイント)も含め、すべての出力値があり、読み取りでそれらが表示されるのは admin スコープを持つキーだけです。インストールのオブジェクトは、以前のレスポンスが返し、後のレスポンスが隠した出力値をそれぞれ保持します。
Catalogue.App rivet = glac.catalogue().get("rivet"); // its parameters, and a month of it in Cube's meters
Installation engine = glac.installations().create("rivet", new InstallationOptions().parameters(Map.of("disk_gib", 20)));
System.out.println(rivet.month() + " " + engine.info().outputs().get("endpoint")); // RIVET_ENDPOINT, its token in it| 呼び出し | 内容 |
|---|---|
glac.catalogue().list(), glac.catalogue().get(app), get(app, version) |
カタログのアプリケーションの一覧。それぞれ Catalogue.App(app、version、title、summary、verified、licence、versions、parameters:JSON Schema、outputs、month、そしてエントリ全体の raw)。1 つのアプリケーション(最新バージョン、または指定したもの)と、raw に入ったその定義 |
glac.installations().create(app), create(app, new InstallationOptions().name(..).version(..).region(..).parameters(..).requires(name, installation).noWait()) |
インストールし、準備ができるまで待つ(noWait ならすぐに戻る)。失敗すると、型とコードが installation_failed の GlacException を、その説明とともにスローする |
glac.installations().list(), list(app), get(idOrName) |
プロジェクトのインストールの一覧(新しい順)。1 つのインストール |
installation.update(new InstallationUpdate().version(..).parameters(..)), delete(), refresh(), await(), await(Duration) |
別のバージョンへの変更、またはパラメーターのマージパッチによる変更(null でデフォルトに戻す)。構成するものごとの削除(status():deleted または deleting)。await(Duration) は wait_timeout で終わり、インストールはそのまま続く |
installation.id(), name(), status(), info() |
API が返すとおり:info() は outputs、secretOutputs、parameters、apps、volumes、buckets、requires、failure を持つ |
マネージドアプリケーションはコントロールプレーンの機能です。
シークレットと変数
- シークレット。
glac.secrets().put("DB_URL", url, List.of("db.example.com"))は、値を名前の下に、送ってよいホストとともに保持します。update(name, hosts)はホストだけを変更し、list()は名前を返し(値は返しません)、delete(name)は 1 つを削除します。アプリの環境変数は、名前でシークレットを受け取り(new AppOptions().secret("VAR", "DB_URL"))、公開されていないイメージ(imagePullSecret)やサンドボックスのエグレスルールも同じです。ほかの場所へ送ることになる呼び出しは、403secret_host_not_allowedで拒否されます。 - 共有変数。
glac.variables().put(name, value)、list()、delete(name):設定した後に作られるバージョンで、サービスのenvが参照する値です("${{ shared.REGION }}")。コントロールプレーンの機能です。
プロジェクト、アカウント、請求
プラットフォームの呼び出しはクライアント自身のものです。glac.project() と glac.events(EventsOptions)(プロジェクトと、そのイベントの 1 ページ分)、glac.account() と glac.updateAccount(AccountOptions)(その月のトラフィック、エグレスの設定、アドレス、通知の言語、請求先住所と税番号)、glac.usage(ListOptions) と glac.usageReport(UsageOptions)(使用量)、glac.billing() と glac.updateBilling(BillingOptions)(プラン、その計測項目とクレジット、サブスクリプション)、glac.balance()、glac.updateBalance(BalanceOptions)、glac.topUp(usd) と glac.topUp(usd, TopUpOptions)(クレジット、自動チャージ、チャージ)、glac.charges()、glac.ledger() です。請求とプロジェクトはコントロールプレーンの機能で、単独で動くノードは自身の 404 を返します。
**イベントのデータ。**コントロールプレーンのイベントの種類ごとに、そのデータのレコードが Event の中にあり、説明のスキーマにちなんだ名前が付いています。その of(event) は、対応する種類のイベントを読み、ほかの種類なら null を返します(Event.Database.of(e))。データベースのもの:Event.Database(database.created:region と PostgreSQL の version 付き。database.deleted:7 日間保持されるドライブのスナップショット final_snapshot_id 付き)、Event.DatabaseBranch(database.branch_created:parent 付き。database.branch_deleted:reason 付き)、Event.DatabaseRestored(database.restored:時点 at と、復元前の状態を保持するブランチ old_branch_id)、Event.DatabaseArchive(database.archive_failing:since、連続して失敗したセグメントの数 failures、その間に復元で遡れる範囲 archived_until、オブジェクトストアの error。database.archive_recovered:recovered_at)、Event.DatabaseGap。ほかも同様です。サンドボックスのもの(Event.SandboxSlept、Event.SandboxWoke、Event.SandboxMoved、Event.SandboxDeleted など)、アプリとそのキーのもの(Event.App、Event.AppFailed、Event.KeyCreated など)、プロジェクトのデプロイとキー、バックアップ、ドメイン、エクスポート先、ドライブのスナップショットのもの(Event.ProjectDeployed、Event.Backup、Event.Domain、Event.Destination、Event.DriveSnapshot など)、そしてアカウントのプラン、チャージ、返金、撤回、残高、クレジット、ストレージ、送信量の上限、利用上限額、保留、未払いのもの(Event.SubscriptionPeriod、Event.TopupCollected、Event.WithdrawalReceived、Event.Balance、Event.InDebt など)です。その種類のすべてのイベントにあるわけではないフィールドや、null のフィールドは null になります(数値のものは Long か Double)。
Webhook、API キー、利用上限額、プロジェクト。glac.webhooks().create(url, new WebhookOptions()…) は、プロジェクトのイベントを自前のアドレスに送ります(各配信に署名する secret() は、このレスポンスにだけ含まれます)。get、list、update、delete もあります。glac.keys().create(name, scopes, expiresAt) は API キーを作ります(キーそのもの key() は、このレスポンスにだけ含まれます)。get、list、delete もあります。glac.limits() と glac.updateLimits(50.0) は、プロジェクトの利用上限額と今月の支出額で(null で上限を外します)、sbx.limits() と sbx.updateLimits(…) はサンドボックス自体のものです。glac.requestLimit(limit, wanted, why) は、アカウントの申請による上限の引き上げを 1 つ申請します(名前で指定する上限、"volumes"、"volume_bytes"。バイト数の 2 つはバイト単位。同じ上限の申請が待機中なら 409 limit_request_pending)。glac.limitRequests(new ListOptions()) と glac.limitRequest(id) は、申請をオペレーターの回答とともに読み取ります(LimitRequest:status は pending、granted、refused。granted、answer)。Event.InstanceRestarted.of(event)、Event.InstanceUpgrade.of(instance.upgraded、.reverted、.upgrade_failed)、Event.LimitRequestAnswer.of は、それらのイベントのデータを読みます。サンドボックス(とインスタンス)の info().startCommand() は、起動コマンドの実行状況、マシン内で再起動された回数、最後の終わり方を示します。glac.updateProject(30) は、スリープが何日続いたらサンドボックスを削除するかを設定します(null なら削除しない)。コントロールプレーンの機能です。Webhook と API キー、プロジェクトの上限の設定、updateProject には admin スコープを持つキーが必要で、サンドボックスの上限の設定には write が必要です。
ログのエクスポート先、監査ログ、請求関連の書類。glac.destinations() は、プロジェクトのアプリのログ(とメトリクス、リクエストのトレース:.signals("logs", "traces"))のエクスポート先(OpenTelemetry のエンドポイント)です。create(name, new DestinationOptions().endpoint(u).header(name, value))(作成時にすぐ 1 件のレコードで試す:status().connected())、get、list、update、delete、test(すぐに 1 件送る)があります。ヘッダーの値は認証情報で、エクスポート先の作成時か変更時に送られ、どのレスポンスにも含まれません(返されるのはヘッダーの名前だけです)。glac.audit(new ListOptions().limit(n)) は、プロジェクトの監査ログの 1 ページ分を新しい順に返します(実行者、メソッド、パス、ステータス)。読み取り以外のすべての呼び出し(拒否されたものも含む)と、オペレーターによるアプリのログの読み取りすべてです。glac.statement("2026-09") は 1 か月の明細(null なら今月)で、データベースごとの行(databases():その月の使用量、履歴と階層化データを別記したもの、それを定価で換算した額)を含みます。glac.invoices() は Stripe にある請求書(PDF のリンク付き)、glac.notices() はアカウントに送られたメール、glac.withdrawals(new ListOptions()) は今撤回できる購入と行った撤回(EEA または英国の消費者は、購入から 14 日以内であれば撤回できます)、glac.withdraw(chargeId, name, email) は購入者自身による撤回の意思表示で、すぐに受理されます。コントロールプレーンの機能です。エクスポート先の作成、変更、テスト、削除、監査ログの読み取り、撤回には admin スコープを持つキーが、それ以外には読み取りのできるキーが必要です。
アカウントの email() は通知の送信先で、new AccountOptions().email(address) で設定します。emailVerified() は確認済みかどうか(メールが送られるのは確認済みのアドレスだけで、そうでないアドレスには先にリンクが送られます)を、emailUndeliverable()(Account.EmailUndeliverable:why、since、detail)はそのアドレスへのメールが不達だったことを示し、その間、通知は保留されます(通知の送信先)。アカウントの language() は通知の言語です(Account.Language:code は “en”、“de”、“fr”、source は “account”、“billing_address”、“default”)。new AccountOptions().language("de") で選び、noLanguage() で選択を取り消すと、再び請求先住所で決まります。撤回の受領通知と購入の確認はこの言語で書かれ、それ以外の通知はすべて英語です。
アカウントの keeps()(Account.Keeps。コントロールプレーンの背後にある場合。単独のノードでは null)は、キーのプロジェクトが保持するドライブとボリュームを、作成時に適用される数値(403 drive_limit_reached、volume_limit_reached)で、それぞれプロジェクトが持っている量とともに示します。volumes(Account.KeepsCount:limit、used、“plan” か “operator” の source)、volumeBytes(Account.KeepsSize:1 つの最大サイズと、その source)、volumesBytes(Account.KeepsTotal:全体の合計サイズの上限。上限なしなら limit は null。そして used)、そしてサイズを指定せずに作った場合のサイズ unsizedBytes です。アカウント独自の数値(“operator”)は、glac.requestLimit("volumes", …) か "volume_bytes" で申請します。
**すぐに受け取る購入(startNow)。**欧州経済領域または英国の消費者(確認済み、または確認中の税番号を持たないアカウント)は、購入から 14 日以内であれば撤回でき、購入したものがすぐに提供されるのは、本人が明示的に求めた場合だけです。startNow() がその要求を伝えます。glac.topUp(20, new TopUpOptions().startNow())、new BillingOptions().plan("paid").startNow()(無料プランから購入する有料プラン)、new BalanceOptions().autoReload(true).startNow()(自動チャージがオンの間のすべての自動チャージ)で、コンソールのチェックボックスの横に表示される文言(GET /v1/billing/withdrawals の right.start_now にもあるもの)で伝えます。
撤回できる 14 日間のうちに、この購入をすぐに提供するよう求めます。撤回した場合は、それまでに提供された分を支払います。チャージのクレジットをすべて使った時点で全額が提供されたことになり、それ以降は撤回できなくなることを理解しています。
サービスはすぐに始まります。14 日以内なら購入者はまだ撤回でき、その場合はそれまでに提供された分を支払います。すべてが提供されると(チャージのクレジットをすべて使うと)、撤回する権利はなくなります。この要求は、購入する本人が求めたときだけ指定してください。SDK は、指定されない限り決して送りません。指定がなければ、そのようなアカウントは拒否されます。ステータス 400、コード start_now_required、param() が start_now の GlacException で、国名を挙げ、要求の文言を引用したメッセージが付き、何も購入されません。要求なしで自動チャージをオンにしたアカウントでは何もチャージされず、月に 1 回通知されます(イベント auto_reload.no_request。Event.AutoReloadNoRequest.of で読みます。カードが登録されていないアカウントでは auto_reload.no_card と Event.AutoReloadNoCard)。
エラー
0 以外の終了コードは結果です。res.exitCode() を読んでください。API のエラーは、status()、type()、code()、param()、retryable()、requestId()、message()、そしてエラーのページの該当するコードを指す docsUrl() を持つ GlacException をスローします。応答のなかった呼び出しも同じです(status() は 0、type() は unavailable か timeout)。どの製品の呼び出しであっても、これはプラットフォームのエラーです。お金に関するエラー(402 account_in_debt、403 trust_limit_exceeded、409 no_card、400 start_now_required など)は、コントロールプレーン自身のメッセージを持ち、解除する方法を示します。
知っておくべき動作
- **スリープ中のサンドボックス。**サンドボックスがスリープ中や起動中であることを理由に失敗する呼び出しはありません。待ってから続行します。
res.wake()は、runが復帰をどれだけ待ったかを示します。クライアントのonResponseは、すべての呼び出しについてそれを受け取ります。 - **再試行。**応答がない場合や
retryableのエラーは、0.2 秒から倍々に間隔を空けて 2 回再試行されます(retries)。すべてのPOSTにはIdempotency-Keyが付きます。idempotencyKey(key)を使えば、再起動したプログラムが、以前に作ったものを取り戻せます。 - タイムアウト。
timeout(指定しなければ 15 分)は API を待つ時間で、RunOptions.timeoutはコマンド自体の制限時間です。 - スレッド。
Glac、その名前空間、Sandbox、Command、ファイルのオブジェクトは、複数のスレッドから使えます。SDK は、イベントストリームを監視する独自のデーモンスレッドを 1 つ起動します。