Changing supervisor processes dynamically through PHP APIs - php

I have setup Supervisor, which I use to manager my worker processes.
Now, I want to dynamically change the processes (stop some processes and start new ones) through the use of PHP APIs.
I found this library which seems to be useful for what I am trying. Specifically, I am using this to change the configuration and this to manage supervisor.
I have set this library up and have the following sample code which seems to work well (from here and here)
<?php
require './vendor/autoload.php';
use Supervisor\Supervisor;
use Supervisor\Connector\XmlRpc;
use fXmlRpc\Client;
use fXmlRpc\Transport\HttpAdapterTransport;
use Ivory\HttpAdapter\Guzzle5HttpAdapter;
use Supervisor\Configuration\Configuration;
use Supervisor\Configuration\Section\Supervisord;
use Supervisor\Configuration\Section\Program;
use Indigo\Ini\Renderer;
//Create GuzzleHttp client
$guzzleClient = new \GuzzleHttp\Client(['auth' => ['user', '123']]);
// Pass the url and the guzzle client to the XmlRpc Client
$client = new Client(
'http://127.0.0.1:9001/RPC2',
new HttpAdapterTransport(new Guzzle5HttpAdapter($guzzleClient))
);
// Pass the client to the connector
// See the full list of connectors bellow
$connector = new XmlRpc($client);
$supervisor = new Supervisor($connector);
$processes = $supervisor->getAllProcesses();
foreach ($processes as $key => $processInfo) {
echo $processInfo . "\r\n";
}
try{
$supervisor->stopProcess('video_convert_02');
}
catch(Exception $e){
echo "\r\n Exception-> " . $e->getMessage();
}
$config = new Configuration;
$renderer = new Renderer;
$section = new Supervisord(['identifier' => 'supervisor']);
$config->addSection($section);
$section = new Program('test', ['command' => 'cat']);
$config->addSection($section);
echo "\r\n Config \r\n" . $renderer->render($config->toArray());
//Not sure how to use this config information to launch supervisor processes.
?>
The output to this is as follows:
pdf_convert_00
pdf_convert_01
video_convert_00
video_convert_01
video_convert_02
video_convert_03
Exception-> BAD_NAME: video_convert_02
Config
[supervisord]
identifier = supervisor
[program:test]
command = cat
I have two questions here:
I dont understand why it throws an exception, when I try to stop the process and
How do I use the config information to launch new processes?

I didn't use this library but "BAD_NAME" error means there is no such process with this name in your configuration.
Btw if you need only to call Supervisor API you can use SupervisorXMLRPC library. Which simply forwards your requests to the Supervisor.
$supervisor = new \Supervisor\Api('127.0.0.1', 9001, 'user', '123');
$processes = $supervisor->getAllProcessInfo();
foreach ($processes as $processInfo) {
print_r($processInfo);
}
try {
$supervisor->stopProcess('video_convert_02');
}
catch (\Supervisor\ApiException $e){
echo "\r\n Exception-> " . $e->getMessage();
}

Related

Google HTTP Target tasks: Expect Google\Protobuf\Timestamp when tried to setScheduleTime using php

I have been trying to add setScheduleTime to the cloud task. I have done the following:
use Google\Cloud\Tasks\V2\CloudTasksClient;
use Google\Cloud\Tasks\V2\HttpMethod;
use Google\Cloud\Tasks\V2\HttpRequest;
use Google\Cloud\Tasks\V2\Task;
class CreateRandomCloudTasksForLot
{
putenv('GOOGLE_APPLICATION_CREDENTIALS=/service-account.json');
$client = new CloudTasksClient();
$queueName = $client->queueName($this->projectID, $this->location, $this->queue);
$httpRequest = new HttpRequest();
$httpRequest->setUrl('https://europe-west1-myproject.cloudfunctions.net/mybidfunction?id=1');
$httpRequest->setHttpMethod(HttpMethod::GET);
if (isset($payload)) {
$httpRequest->setBody($payload);
}
// Create a Cloud Task object.
$task = new Task();
$task->setScheduleTime(strtotime(Carbon::now()->addMinutes(20)));
$task->setHttpRequest($httpRequest);
// Send request and print the task name.
$response = $client->createTask($queueName, $task);
printf('Created task %s' . PHP_EOL, $response->getName());
}
It gives me the following error
Without passing the scheduled time I can create tasks but I need to schedule at a specific time. I cannot use appEngineTask because we can pass only RelativeUri. I want to pass the cloud function URL to execute. Can anyone please help me?
I found the issue. Hope it will help someone because they have not mentioned in their document at all.
add this use Google\Protobuf\Timestamp;
$future_time_seconds = time() + 300;
$future_timestamp = new Timestamp();
$future_timestamp->setSeconds($future_time_seconds);
$future_timestamp->setNanos(0);
$task->setScheduleTime($future_timestamp);
$task->setHttpRequest($httpRequest);
Pass the object of Google\Protobuf\Timestamp to setScheduleTime. After digging into core files I figure out that it should be an object. The error should be more descriptive.
That's all :)

Error while importing Quickbook library in Laravel 5.3

I am integrating quickbooks with my laravel app. After integration I got this error,
PHP Warning: require_once(../QuickBooks.php): failed to open stream:
No such file or directory in
/home/vipin/projects/development/Quickbook/config/app.php on line 2
PHP Fatal error: require_once(): Failed opening required '../QuickBooks.php'
(include_path='.:/usr/share/php:/home/ubuntu/projects/development/Quickbook/vendor/consolibyte/quickbooks')
in /home/ubuntu/projects/development/Quickbook/config/app.php on line
2
Here is my controller Quickbook.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
// require_once '../QuickBooks.php';
use App\Http\Requests;
class QuickBooksController extends Controller
{
private $IntuitAnywhere;
private $context;
private $realm;
public function __construct(){
if (!\QuickBooks_Utilities::initialized(env('QBO_DSN'))) {
// Initialize creates the neccessary database schema for queueing up requests and logging
\QuickBooks_Utilities::initialize(env('QBO_DSN'));
}
$this->IntuitAnywhere = new \QuickBooks_IPP_IntuitAnywhere(env('QBO_DSN'), env('QBO_ENCRYPTION_KEY'), env('QBO_OAUTH_CONSUMER_KEY'), env('QBO_CONSUMER_SECRET'), env('QBO_OAUTH_URL'), env('QBO_SUCCESS_URL'));
}
public function qboConnect(){
if ($this->IntuitAnywhere->check(env('QBO_USERNAME'), env('QBO_TENANT')) && $this->IntuitAnywhere->test(env('QBO_USERNAME'), env('QBO_TENANT'))) {
// Set up the IPP instance
$IPP = new \QuickBooks_IPP(env('QBO_DSN'));
// Get our OAuth credentials from the database
$creds = $this->IntuitAnywhere->load(env('QBO_USERNAME'), env('QBO_TENANT'));
// Tell the framework to load some data from the OAuth store
$IPP->authMode(
\QuickBooks_IPP::AUTHMODE_OAUTH,
env('QBO_USERNAME'),
$creds);
if (env('QBO_SANDBOX')) {
// Turn on sandbox mode/URLs
$IPP->sandbox(true);
}
// This is our current realm
$this->realm = $creds['qb_realm'];
// Load the OAuth information from the database
$this->context = $IPP->context();
return true;
} else {
return false;
}
}
public function qboOauth(){
if ($this->IntuitAnywhere->handle(env('QBO_USERNAME'), env('QBO_TENANT')))
{
; // The user has been connected, and will be redirected to QBO_SUCCESS_URL automatically.
}
else
{
// If this happens, something went wrong with the OAuth handshake
die('Oh no, something bad happened: ' . $this->IntuitAnywhere->errorNumber() . ': ' . $this->IntuitAnywhere->errorMessage());
}
}
public function qboSuccess(){
return view('qbo_success');
}
public function qboDisconnect(){
$this->IntuitAnywhere->disconnect(env('QBO_USERNAME'), env('QBO_TENANT'),true);
return redirect()->intended("/yourpath");// afer disconnect redirect where you want
}
public function createCustomer(){
$CustomerService = new \QuickBooks_IPP_Service_Customer();
$Customer = new \QuickBooks_IPP_Object_Customer();
$Customer->setTitle('Ms');
$Customer->setGivenName('Shannon');
$Customer->setMiddleName('B');
$Customer->setFamilyName('Palmer');
$Customer->setDisplayName('Shannon B Palmer ' . mt_rand(0, 1000));
// Terms (e.g. Net 30, etc.)
$Customer->setSalesTermRef(4);
// Phone #
$PrimaryPhone = new \QuickBooks_IPP_Object_PrimaryPhone();
$PrimaryPhone->setFreeFormNumber('860-532-0089');
$Customer->setPrimaryPhone($PrimaryPhone);
// Mobile #
$Mobile = new \QuickBooks_IPP_Object_Mobile();
$Mobile->setFreeFormNumber('860-532-0089');
$Customer->setMobile($Mobile);
// Fax #
$Fax = new \QuickBooks_IPP_Object_Fax();
$Fax->setFreeFormNumber('860-532-0089');
$Customer->setFax($Fax);
// Bill address
$BillAddr = new \QuickBooks_IPP_Object_BillAddr();
$BillAddr->setLine1('72 E Blue Grass Road');
$BillAddr->setLine2('Suite D');
$BillAddr->setCity('Mt Pleasant');
$BillAddr->setCountrySubDivisionCode('MI');
$BillAddr->setPostalCode('48858');
$Customer->setBillAddr($BillAddr);
// Email
$PrimaryEmailAddr = new \QuickBooks_IPP_Object_PrimaryEmailAddr();
$PrimaryEmailAddr->setAddress('support#consolibyte.com');
$Customer->setPrimaryEmailAddr($PrimaryEmailAddr);
if ($resp = $CustomerService->add($this->context, $this->realm, $Customer))
{
//print('Our new customer ID is: [' . $resp . '] (name "' . $Customer->getDisplayName() . '")');
//return $resp;
//echo $resp;exit;
//$resp = str_replace('{','',$resp);
//$resp = str_replace('}','',$resp);
//$resp = abs($resp);
return $this->getId($resp);
}
else
{
//echo 'Not Added qbo';
print($CustomerService->lastError($this->context));
}
}
public function addItem(){
$ItemService = new \QuickBooks_IPP_Service_Item();
$Item = new \QuickBooks_IPP_Object_Item();
$Item->setName('My Item');
$Item->setType('Inventory');
$Item->setIncomeAccountRef('53');
if ($resp = $ItemService->add($this->context, $this->realm, $Item))
{
return $this->getId($resp);
}
else
{
print($ItemService->lastError($this->context));
}
}
public function addInvoice($invoiceArray,$itemArray,$customerRef){
$InvoiceService = new \QuickBooks_IPP_Service_Invoice();
$Invoice = new \QuickBooks_IPP_Object_Invoice();
$Invoice = new QuickBooks_IPP_Object_Invoice();
$Invoice->setDocNumber('WEB' . mt_rand(0, 10000));
$Invoice->setTxnDate('2013-10-11');
$Line = new QuickBooks_IPP_Object_Line();
$Line->setDetailType('SalesItemLineDetail');
$Line->setAmount(12.95 * 2);
$Line->setDescription('Test description goes here.');
$SalesItemLineDetail = new QuickBooks_IPP_Object_SalesItemLineDetail();
$SalesItemLineDetail->setItemRef('8');
$SalesItemLineDetail->setUnitPrice(12.95);
$SalesItemLineDetail->setQty(2);
$Line->addSalesItemLineDetail($SalesItemLineDetail);
$Invoice->addLine($Line);
$Invoice->setCustomerRef('67');
if ($resp = $InvoiceService->add($this->context, $this->realm, $Invoice))
{
return $this->getId($resp);
}
else
{
print($InvoiceService->lastError());
}
}
public function getId($resp){
$resp = str_replace('{','',$resp);
$resp = str_replace('}','',$resp);
$resp = abs($resp);
return $resp;
}
}
Config/app.php
<?php
require_once '../QuickBooks.php';
return [
'qbo_token' => env('QUICKBOOK_TOKEN'),
'qbo_consumer_key' => env('QBO_OAUTH_CONSUMER_KEY'),
'qbo_consumer_secret' => env('QBO_CONSUMER_SECRET'),
'qbo_sandbox' => env('QBO_SANDBOX'),
'qbo_encryption_key' => env('QBO_ENCRYPTION_KEY'),
'qbo_username' => env('QBO_USERNAME'),
'qbo_tenant' => env('QBO_TENANT'),
'qbo_auth_url' => 'http://app.localhost:8000/qbo/oauth',
'qbo_success_url' => 'http://app.localhost:8000/qbo/success',
'qbo_mysql_connection' => 'mysqli://'. env('DB_USERNAME') .':'. env('DB_PASSWORD') .'#'. env('DB_HOST') .'/'. env('DB_DATABASE'),
There are several areas to improve on here with the given code & approach.
As Anton correctly points out, you should not be directly requiring any of the quickbooks library files. If you've loaded this in via Composer then they will be automatically loaded because the Composer autoloader will load the QuickBooks file from the vendor. This is correct for Laravel as well as general Composer-based applications - the only difference with Laravel is that there isn't a specific Laravel Package ServiceProvider that's been written for this SDK, but that doesn't matter.
The QuickBooks library tries to jump on top of autoloading any class that starts with 'QuickBooks', so you're better off making a QuickBooks folder for your controller class. This is more of a 'gotcha' and has been pointed out in the repo issues.
The reason you're getting the Driver/.php error is because you have not specified your QBO_DSN, or have done so incorrectly - this DSN environment variable that you're passing to the initialisation is being run through parse_url() in the SDK code, coming up false or null and breaking the auto-loader for initalisation. If this was set to a proper connection string (e.g. mysqli://username:password#host:port/database and note that port must be a number or it's considered malformed), it would correctly process the DSN and continue to load the page. Be aware that initialisation will attempt to parse and fetch the network address of the host, so you can't just put a dummy value in there and expect it to work - this needs to exist first.
You're mixing your environment variables and application configuration, without using either of them properly. If you wanted your DB connection string (a.k.a. QBO_DSN) to be constructed a particular way into the application configuration setting qbo_mysql_connection, then you should be using the configuration setting when trying to initialise/load/etc. Instead of using env('QBO_DSN'), you should be using config('app.qbo_mysql_connection') to load the constructed version from your app settings. Typically you would not be loading so many environment variables into a controller at all - that should be handled by the application, and then the controller calling the application configuration so it's agnostic of how they were defined.
You shouldn't need to require anything from inside the app configuration file either - that file is just for configuration variables being set up.
Since the QuickBooks SDK isn't properly namespaced (yet), there isn't a nice PSR-4 way of loading (and use-ing) the classes, but it's still good practice to use use clauses at the top of the file (e.g. use QuickBooks_Utilities;) so that you can use the classes without fear of forgetting the preceding backslash (i.e. no more \QuickBooks_Utilities, just QuickBooks_Utilities in usage) - there are several instances in the given code where this has been forgotten, and will not work because the Laravel application is namespaced and will look for those classes in the App\Http\Controllers namespace (e.g. errors like "Cannot find class App\Http\Controllers\QuickBooks_Utilities").
Indentation - pick a style (e.g. tabs, 2-space, PSR-2, etc) and then stick to it. Run phpcs or some other clean-up tool over all of your code before committing to your repository or posting on SO - readability is important!
Using require instead of autoloader is a bad practice in modern frameworks (and generally in modern PHP). I highly recommend using the package manager (eg composer) to properly add modules to the project.
For example, to add a quickbooks library into the project using composer, you need to run only one command:
composer require consolibyte/quickbooks
Add this line in footer of Config/app.php
require_once '../QuickBooks.php';

How to run exec()/ linux commands using gearman extension from cakephp application?

I installed gearman extension and gearman command line tool also. I tried to reverse a string using gearman from simple php file.
Example:
$gmclient= new GearmanClient();
$gmclient->addServer();
$result = $gmclient->doNormal("reverse", "Test the reverse string");
echo "Success: $result\n";
output:
Success: gnirts esrever eht tseT
In the same way i tried to run exec('ls -l') , I am able to execute using simple php files from cakephp application from webroot directory. filepath: cakephp/app/webroot/worker.php, cakephp/app/webroot/client.php.
worker.php
<?php
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction("exec", "executeScript");
while ($worker->work());
function executeScript($job)
{
$param = $job->workload();
$t = exec($param);
return $t;
}
?>
client.php
<?php
$client= new GearmanClient();
$client->addServer();
$cmd = 'ls -l';
print $client->do("exec", $cmd);
?>
How to implement the same type of execution using View, Controller from cakephp?
Workflow: Post data from View to Controller using ajax method and execute "exec() from gearman" , send output back to View as response of ajax POST methhod.
Why are you using exec?! That brings a huge security risk. Use DirectoryIterator instead.
Your client code should be part of the controller.
<?php
class UploadController extends AppController
{
public function directoryList()
{
$directory = '';
// Get data
if (!empty($this->data['directory']) && is_string($this->data['directory']))
{
$directory = $this->data['directory'];
}
$client= new GearmanClient();
$client->addServer("localhost",4730); // Important!!!
$result = $client->do("fileList", serialize($data));
return $result;
}
}
Then from view use requestAction.
$uploads = $this->requestAction(
array('controller' => 'upload', 'action' => 'directoryList'),
array('return')
);
Worker could look like this:
<?php
$worker= new GearmanWorker();
$worker->addServer("localhost",4730); // Important!!!
$worker->addFunction("fileList", "getFileList");
while ($worker->work());
// From Art of Web
// http://www.the-art-of-web.com/php/directory-list-spl/
function getFileList($dir)
{
// array to hold return value
$retval = array();
$dir = $job->workload();
// add trailing slash if missing
if(substr($dir, -1) != "/") $dir .= "/";
// open directory for reading
$d = new DirectoryIterator($dir) or die("getFileList: Failed opening directory $dir for reading");
foreach($d as $fileinfo) {
// skip hidden files
if($fileinfo->isDot()) continue;
$retval[] = array(
'name' => "{$dir}{$fileinfo}",
'type' => ($fileinfo->getType() == "dir") ?
"dir" : mime_content_type($fileinfo->getRealPath()),
'size' => $fileinfo->getSize(),
'lastmod' => $fileinfo->getMTime()
);
}
return $retval;
}
This is pseudo code. Do not use it in production!!! See Gearman documentation for more advance worker setup.
To actually take advantage of load distribution Gearman server should not be on localhost of course.
Your worker.php needs to be already running on a server for this to work. For testing, open up a new terminal window to the server where you want worker.php to run. Start the worker: php worker.php on the command line. (On a production server, you might want to look at supervisor to run your worker without a terminal.)
The code in client.php would go in your controller, but save the result to a variable instead of a print statement.
The fact that this would be from an AJAX call is irrelevant, it will work the same as a normal web page. When the controller executes, the gearman client code will get a response from the worker, and you can output the result to the view.

How to connect with OpenFire(xmpp) using RESTAPI plugin And PHP

I am using OpenFire to manage my xmpp server I want to add new users using a PHP, So I have installed RESETAPI Plugin to OpenFire to administrate with http request. I am using gidkom Project also. But getting a error
Parse error: syntax error, unexpected T_VARIABLE in C:\wamp\www\IM\registration.php on line 12
My code for registration.php is:
<?php
if(isset($_POST["User_Name"]) && isset($_POST["Name"]) )
{
$User_ID = $_POST["User_Name"];
$User_Name = $_POST["Name"];
$User_Email = $_POST["Email"];
include "Gidkom/OpenFireRestApi/OpenFireRestApi.php";
// Create the OpenfireUserservice object
$api = new Gidkom\OpenFireRestApi
// Set the required config parameters
$api->secret = "my keys";
$api->host = "domain.my.org";
$api->port = "9090"; // default 9090
// Optional parameters (showing default values)
$api->useSSL = false;
$api->plugin = "/plugins/restapi/v1"; // plugin
// Add a new user to OpenFire and add to a group
$result = $api->addUser($User_ID, 'Password', $User_Name, $User_Email, array('welcome'));
// Check result if command is succesful
if($result['status']) {
// Display result, and check if it's an error or correct response
echo 'Success: ';
echo $result['message'];
} else {
// Something went wrong, probably connection issues
echo 'Error: ';
echo $result['message'];
}
//Add to roster
$api->addToRoster('Administrator', 'admin');
}
else
{
echo 'Error: Something went wrong..... please go back ';
}
I want the page to add a new new user in the openfire and add admin to his roster.
Thanks !!!!
Semicolon is missing.
$api = new Gidkom\OpenFireRestApi\OpenFireRestApi;
The errors were caused because of an outdated version of PHP, YPdating PHP to latest version fixed it...
prerequirements: must to have composer.exe installed on your machine
from cmd.exe
go to your web root server(htdocs) then
go into your directory which contain the rest api sources
then from this cmd.exe(or create one batch)
c:/..../....> composer install
Remark: -this commnad(composer install) must to have in same directory the composer.json
-this command(composer install) will create one subdirectory "vendor" named
now into your index.php must insert on top, the following line:
<?php
include "vendor/autoload.php";
....
and continue your actual program
and is trully must to end the lines with ;
...
?
https://github.com/gnello/php-openfire-restapi
Easy Php REST API Client for the Openfire REST API Plugin which provides the ability to manage Openfire instance by sending an REST/HTTP request to the server
Please read documentation for further information on using this application.
Installation
composer require gnello/php-openfire-restapi
Authentication
There are two ways to authenticate:
Basic HTTP Authentication
$authenticationToken = new \Gnello\OpenFireRestAPI\AuthenticationToken('your_user', 'your_password');
Shared secret key
$authenticationToken = new \Gnello\OpenFireRestAPI\AuthenticationToken('your_secret_key');
Start
$api = new \Gnello\OpenFireRestAPI\API('your_host', 9090, $authenticationToken);
Users
//Add a new user
$properties = array('key1' => 'value1', 'key2' => 'value2');
$result = $api->Users()->createUser('Username', 'Password', 'Full Name', 'email#domain.com', $properties);
//Delete a user
$result = $api->Users()->deleteUser('Username');
//Ban a user
$result = $api->Users()->lockoutUser('Username');
//Unban a user
$result = $api->Users()->unlockUser('Username');
Open Link Fore more.

Amazon AWS PHP SDK with Guzzle's MultiCurl?

I need to perform some fairly heavy queries with Amazon's AWS SDK for PHP.
The most efficient way would be to use PHP's MultiCurl. It seems that Guzzle already has functionality for MultiCurl built in.
Does using the standard methods provided by the AWS SDK automatically use MultiCurl or do I have to specify it's usage directly? E.g. calling $sns->Publish() 30 times.
Thanks!
Parallel requests work exactly the same in the SDK as in plain Guzzle and do take advantage of MultiCurl. For example, you could do something like this:
$message = 'Hello, world!';
$publishCommands = array();
foreach ($topicArns as $topicArn) {
$publishCommands[] = $sns->getCommand('Publish', array(
'TopicArn' => $topicArn,
'Message' => $message,
));
}
try {
$successfulCommands = $sns->execute($publishCommands);
$failedCommands = array();
} catch (\Guzzle\Service\Exception\CommandTransferException $e) {
$successfulCommands = $e->getSuccessfulCommands();
$failedCommands = $e->getFailedCommands();
}
foreach ($failedCommands as $failedCommand) { /* Handle any errors */ }
$messageIds = array();
foreach ($successfulCommands as $successfulCommand) {
$messageIds[] = $successfulCommand->getResult()->get('MessageId');
}
// Also Licensed under version 2.0 of the Apache License.
The AWS SDK for PHP User Guide has more information about working with command objects in this way.

Categories