scalr / fatmouse-phpclient
Fatmouse PHP 客户端
Requires
- php-amqplib/php-amqplib: 2.6.3
Requires (Dev)
- phpunit/phpunit: 5.0.10
- squizlabs/php_codesniffer: 2.5.0
This package is not auto-updated.
Last update: 2017-10-05 04:36:37 UTC
README
FatMouse 为 Scalr 提供了一个 PHP 客户端,用于集成。
composer install
测试
测试在 devbox 中执行。
配置 devbox
sudo -E fab -f provision/linux/fabfile.py pull retag phpclient
启动 Fatmouse
- 本地使用
docker-compose up - 或远程设置
FAM_PHPCLIENT_BROKER_URL
运行套件
cd phpclient
./vendor/bin/phpunit -v tests/large
示例
初始化 PHP 客户端
<?php $broker = "amqp://fatmouse-api.scalr-labs.com"; $fatmouse = new Fatmouse\Fatmouse($broker);
调用服务器任务。通用
<?php use Fatmouse\Errors; $timeout = 30 $taskName = "register_server"; $params = [ "server_id" => "cf3a320b-7ac6-4b88-810a-c760a94e1875", "env_id" => "7743d825-9792-46bc-827f-285882f58fb2" ]; $asyncResult = $fatmouse->callAsync($taskName, $params); try { $task = $asyncResult->wait(); var_dump($task->getResult()); } finally { // Acknowledge result to remove it from queue $asyncResult->ack(); }
调用服务器任务。Sugar
<?php use Fatmouse\Errors; try { $asyncResult = $fatmouse->registerServer($serverId, $envId); try { $reg = $asyncResult->wait()->getResult(); print("Server registered!") var_dump($reg->agentConfig); } finally { $asyncResult->ack(); } } catch (\Exception $e) { printf("Server registration failed %s: %s", get_class($e), $e->getMessage()); }
在一个进程中调用服务器任务,在其他进程中获取结果
进程 1
<?php $asyncResult = $fatmouse->callAsync($taskName, $params); $taskId = $asyncResult->getTaskId(); // Then pass $taskId to Process 2
进程 2
<?php $asyncResult = $fatmouse->newAsyncResult($taskId, $taskName); $task = $asyncResult->wait(); try { $task->getResult(); } finally { $asyncResult->ack(); }
调用 Scalarizr 任务。通用
<?php $serverId = "cf3a320b-7ac6-4b88-810a-c760a94e1875"; $taskName = "sys.set_hostname"; $params = ["hostname" => "my.example.com"]; $timeout = 5; $result = $fatmouse->callAgentSync($serverId, $taskName, $params, $timeout);
调用 Scalarizr 任务。Sugar
<?php $fatmouse->agent($serverId)->sys->setHostname("my.example.com"); // control timeout $fatmouse->agent($serverId, ['timeout' => 30])->sys->setHostname("my.example.com");
消费事件
<?php $callback = function ($event) { printf( "Received event %s (ID: %s) with payload: %s", $event->name, $event->eventId, var_export($event->getPayload(), true) ); // After result was handled, it should be acknowledged to prevent repeating handling $event->ack(); } $fatmouse->initEventConsumer($callback); $timeout = 1; while (true) { try { // poll for event until timeout $fatmouse->consumeEvent($timeout); } catch (\Exception $e) { print("Event loop error: %s" . $e->getMessage()); } }
在 FatMouse 中注册 Scalr 管理服务器
Fatmouse 应该知道 Scalr 启动和终止的每个服务器。
当 Scalr 即将启动新服务器时,它应该调用 registerServer()。
然后,处理结果数据
- 将
$reg->agentConfig导出为 JSON 并将其注入到云服务器中的/etc/scalr/agent.json - 在
$reg->agentConfig['CELERY']['BROKER_URL']中编辑主机名到公 DNS 名称
要运行 Scalr 管理服务器,需要在它上安装代理。这可以通过 CloudInit 轻松委托。取 user-data.tpl.sh,将其中的 %AGENT_JSON% 替换为 JSON 数据,并将结果脚本作为用户数据拉取到云提供商的创建服务器 API 调用中。您使用的镜像应该支持 cloud-init(Ubuntu、Amazon Linux)
<?php // When Scalr has launched new server $asyncResult = $fatmouse->registerServer($serverId, $envId); $reg = $asyncResult->wait()->getResult(); // agent.json data var_dump($reg->agentConfig);
当 Scalr 终止服务器时,它应该调用 deregisterServer()。任务没有结果值
<?php // When Scalr terminates server $fatmouse->deregisterServer();
执行工作流
如果您不熟悉工作流,请 阅读简介
为了初始化服务器,Scalr 应该运行 init 工作流。
<?php use \Fatmouse\Errors; $asyncResult = $fatmouse->workflows()->init($params); $init = $asyncResult->wait(); try { var_dump($init->getResult()); // output workflow result if ($init->isHalfCompleted()) { foreach ($init->failedTasks as $task) { printf('Task "%s" %s(%s) error: %s', $task->title, $task->name, $task->taskId, $task->getException()->getMessage() ); } } catch (Errors\ServerException $e) { // handle error printf('Workflow %s(%s) error: %s', $init->getName(), $init->getTaskId(), $e->getMessage() ); } finally { $asyncResult->ack(); // Acknowlenge result and remove it from queue }
调用代理
可以直接调用代理任务而无需工作流。这对于从 Scalr 以 RPC 方式直接获取各种 OS 信息、日志、度量很有用。
此示例将获取服务器 CPU 统计信息
<?php use Fatmouse\Agent\Fact; $serverId = 'd20dc26c-6220-4df8-996a-92f09d710524'; $stat = $fatmouse->agent($serverId)->sys->getFact(Fact::STAT_CPU); var_dump($stat); /* Output array(4) { ["nice"]=> int(0) ["user"]=> int(8416) ["system"]=> int(6754) ["idle"]=> int(147309) } */
接收事件
FatMouse 触发各种事件,应该被监听和处理。
处理服务器重启
<?php use Fatmouse\Events; $callback = function ($event) { $pay = $event->getPayload(); if ($pay instanceof Events\ServerRebooted)) { // Server was rebooted printf( 'Server %s was rebooted at %s, and new boot_id is: %s', $pay->serverId, $event->firedAt, $pay->bootId ); } else { // default event handler } // acknowledge event, so it'll be never received by other workers // all received events should be acknowledged, or they will come again. $event->ack(); } $timeout = 1; $fatmouse->initEventConsumer($callback); while (true) { $fatmouse->consumeEvent($timeout); }
处理编排工作流进度
<?php use Fatmouse\Agent; use Fatmouse\Events; $asyncResult = $fatmouse->workflows()->orchestration(...); $workflowId = $asyncResult->getTaskId(); $callback = function ($event) { $pay = $ev->getPayload(); // track scripts and chef tasks status if ($pay instanceof Events\TaskFinished && $pay->workflow && $pay->workflow->taskId == $workflowId && in_array($pay->task->name, [ Agent\TaskName::EXECUTE, Agent\TaskName::CHEF_SOLO, Agent\TaskName::CHEF_CLIENT ]) ) { // Push notification to js // // Example output: // [orchestration] task chef.solo(deploy application) on 83888...4f9368a COMPLETED // [orchestration] task execute(reload crontab) on d9f82a12...740a28 COMPLETED // [orchestration] task execute(danger staff) on d9f82a12...740a28 FAILED // E: Command exited with non-zero code 2 $js->pushStatus(sprintf( '[%s] task %(%s) on server %s %s', $pay->task->workflow->name, $pay->task->name, $pay->task->title, $pay->serverId, strtoupper($pay->task->status) )); if ($pay->task->isFailed()) { $js->pushStatus(sprintf( 'error: %s', $pay->task->getException()->getMessage() )); } $event->ack(); // acknowledge event! } } $timeout = 1; $fatmouse->initEventConsumer($callback); while (true) { $fatmouse->consumeEvent($timeout); }
处理工作流完成事件
<?php use Fatmouse\Events; use Fatmouse\Errors; use Fatmouse\Workflows; $callback = function ($event) { $pay = $event->getPayload(); if ($pay instanceof Events\WorkflowFinished) { try { $pay->workflow->throwForState(); if ($pay->workflow instanceof Workflows\AgentUpdate) { // agent updated. proceed to orchestration(HostInit) } elseif ($pay->workflow instanceof Workflows\Init) { // initialization completed $pay->workflow->getResult(); // HostUp like data } elseif ($pay->workflow instanceof Workflows\Orchestration) { // orchestration completed } elseif ($pay->workflow instanceof Workflows\Volume) { // storage volume created, attached and configured } } catch (Errors\ServerException $e) { // handle workflow error printf('Workflow %s(%s) error: %s', $pay->workflow->name, $pay->workflow->taskId, $e->getMessage() ); } $event->ack(); // acknowledge event! } } $timeout = 1; $fatmouse->initEventConsumer($callback); while (true) { $fatmouse->consumeEvent($timeout); }
完整的服务器初始化过程(HostInit -> HostUp)
1. 注册新服务器。
<?php $reg = $fatmouse->registerServer($serverId)->wait()->getResult();
2. 在云中启动服务器
在云中启动服务器,并在用户数据脚本中将 $reg->agentConfig 传递给服务器代理。 更多关于服务器注册信息
3. 等待 AuthAgent 任务完成
从 authenticate_server 任务接收 task_finished 事件。 了解如何接收事件
<?php use Fatmouse\Events; use Fatmouse\Errors; use Fatmouse\Tasks; $callback = function ($event) { $pay = $event->getPayload(); if ($pay instanceof Events\TaskFinished && $pay->task instanceof Tasks\AuthenticateServer ) { try { $pay->task->throwForState(); printf( 'Server %s successfully authenticated', $pay->task->serverId ); } catch (Errors\ServerException $e) { printf('Server %s authentication error: %s', $pay->task->serverId, $e->getMessage()) } $event->ack(); // acknowledge event! } }
4. 编排 HostInit
创建 HostInit 事件对象并执行 orchestration 工作流。
<?php // TODO: TBD $orc format $ar = $fatmouse->workflows()->orchestration($orc); $result = $ar->wait()->getResult();
了解如何设置回调以异步处理[工作流结果](#Handle Workflow Finished Event)。同样适用于后续步骤。
5. 执行 "init" 工作流
执行 "init" 工作流以初始化服务器。(HostInitResponse 和 BeforeHostUp 之间的阶段)
<?php use \Fatmouse\Types; $init = new Types\InitializationParams() ->withHostName($hostname) ->andVolume($ephemeral_D) ->andVolume($ebs_E) ->andChefAction(new Types\Orchestration\ChefSoloAction() ->withJsonAttributes($jsonAttributes) ->andCookbooks(new Types\Orchestration\CookbookUrlSource() ->withUrl($httpsCookbooksTarGz))); $ar = $fatmouse->workflows()->init($init) $result = $ar->wait()->getResult();
$init 和 $result 包含类似于 HostInitResponse / HostUp 消息的数据
6. 编排 BeforeHostUp
创建 BeforeHostUp 事件对象并执行 orchestration 工作流。
服务器正在运行!Scalr 将服务器添加到 DNS,并执行内部 HostUp 程序
7. 编排 HostUp
创建 HostUp 事件对象并执行 orchestration 工作流。