/** * Make a request to the Dashbord's internal API. * * @param $realm * Permissions realm for data request: currently "user" or "site" but in the * future this could also be "organization" or another high-level business * object (e.g. "product" for managing your app). Can also be "public" to * simply pull read-only data that is not privileged. * * @param $uuid * The UUID of the item in the realm you want to access. * * @param $method * HTTP method (verb) to use. * * @param $data * A native PHP data structure (int, string, arary or simple object) to be * sent along with the request. Will be encoded as JSON for you. */ public static function request($realm, $uuid, $path = FALSE, $method = 'GET', $options = NULL) { if (!in_array($realm, array('login', 'user', 'public'))) { Auth::loggedIn(); } try { $cache = Terminus::get_cache(); if (!in_array($realm, array('login', 'user'))) { $options['cookies'] = array('X-Pantheon-Session' => Session::getValue('session')); $options['verify'] = false; } $url = Endpoint::get(array('realm' => $realm, 'uuid' => $uuid, 'path' => $path)); if (Terminus::get_config('debug')) { Logger::debug('Request URL: ' . $url); } $resp = Request::send($url, $method, $options); $json = $resp->getBody(true); $data = array('info' => $resp->getInfo(), 'headers' => $resp->getRawHeaders(), 'json' => $json, 'data' => json_decode($json), 'status_code' => $resp->getStatusCode()); return $data; } catch (Guzzle\Http\Exception\BadResponseException $e) { $response = $e->getResponse(); \Terminus::error("%s", $response->getBody(true)); } catch (Guzzle\Http\Exception\HttpException $e) { $request = $e->getRequest(); //die(Terminus_Command::stripSensitiveData()); $sanitized_request = Terminus_Command::stripSensitiveData((string) $request, Terminus_Command::$_blacklist); \Terminus::error("Request %s had failed: %s", array($sanitized_request, $e->getMessage())); } catch (Exception $e) { \Terminus::error("Unrecognised request failure: %s", $e->getMessage()); } }
static function getArgsKey($args) { // strip UUIDs $string = preg_replace('#https://dashboard.getpantheon.com/api/(sites|users|ogranizations)\\/(.*)\\/(.+)$#s', '$1/$3', $args[0]); $key = sprintf('%s%s', $args[1], strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $string)))); if (\Terminus::get_config('debug')) { \Terminus\Loggers\Regular::debug(var_export($args, 1)); \Terminus\Loggers\Regular::debug($key); } return $key; }
public static function send($url, $method, $data = array()) { // create a new Guzzle\Http\Client $browser = new Browser(); $browser->setUserAgent(self::userAgent()); $options = array(); $options['allow_redirects'] = @$data['allow_redirects'] ?: false; $options['json'] = @$data['json'] ?: false; if (@$data['body']) { $options['body'] = $data['body']; if (\Terminus::get_config("debug")) { \Terminus\Loggers\Regular::debug($data['body']); } } $options['verify'] = false; $request = $browser->createRequest($method, $url, null, null, $options); if (!empty($data['postdata'])) { foreach ($data['postdata'] as $k => $v) { $request->setPostField($k, $v); } } if (!empty($data['cookies'])) { foreach ($data['cookies'] as $k => $v) { $request->addCookie($k, $v); } } if (!empty($data['headers'])) { foreach ($data['headers'] as $k => $v) { $request->setHeader($k, $v); } } if (\Terminus::get_config("debug")) { $debug = "#### REQUEST ####" . PHP_EOL; $debug .= $request->getRawHeaders(); \Terminus\Loggers\Regular::debug($debug); if (isset($data['body'])) { \Terminus\Loggers\Regular::debug($data['body']); } } if (getenv("BUILD_FIXTURES")) { Fixtures::put("request_headers", $request->getRawHeaders()); } $response = $request->send(); if (getenv("BUILD_FIXTURES")) { Fixtures::put(array($url, $method, $data), $response); } return $response; }
/** * Make a request to the Dashbord's internal API. * * @param $realm * Permissions realm for data request: currently "user" or "site" but in the * future this could also be "organization" or another high-level business * object (e.g. "product" for managing your app). Can also be "public" to * simply pull read-only data that is not privileged. * * @param $uuid * The UUID of the item in the realm you want to access. * * @param $method * HTTP method (verb) to use. * * @param $data * A native PHP data structure (int, string, arary or simple object) to be * sent along with the request. Will be encoded as JSON for you. */ public static function request($realm, $uuid, $path = FALSE, $method = 'GET', $options = NULL) { if (!in_array($realm, array('login', 'user', 'public')) and !Terminus::is_test()) { Auth::loggedIn(); } try { $cache = Terminus::get_cache(); // combine session realm uuid and path to get a unique key // @todo need cache "groups" $cachekey = md5(Session::getValue('user_uuid') . $uuid . $realm . $path); $data = $cache->get_data($cachekey); // check the request cache if ("GET" == $method and !Terminus::get_config('nocache') and !getenv('CLI_TEST_MODE') and !empty($data)) { if (Terminus::get_config('debug')) { Logger::debug('CacheKey: ' . $cachekey); } return (array) $data; } // for some methods we'll assume the cache should be invalidated if (in_array($method, array("POST", "PUT", "DELETE"))) { $cache->flush(null, 'session'); } if (!in_array($realm, array('login', 'user'))) { $options['cookies'] = array('X-Pantheon-Session' => Session::getValue('session')); $options['verify'] = false; } $url = Endpoint::get(array('realm' => $realm, 'uuid' => $uuid, 'path' => $path)); if (Terminus::get_config('debug')) { Logger::debug('Request URL: ' . $url); } $resp = Request::send($url, $method, $options); $json = $resp->getBody(TRUE); $data = array('info' => $resp->getInfo(), 'headers' => $resp->getRawHeaders(), 'json' => $json, 'data' => json_decode($json), 'status_code' => $resp->getStatusCode()); $cache->put_data($cachekey, $data); return $data; } catch (Guzzle\Http\Exception\BadResponseException $e) { $response = $e->getResponse(); \Terminus::error("%s", $response->getBody(TRUE)); } catch (Guzzle\Http\Exception\HttpException $e) { $request = $e->getRequest(); //die(Terminus_Command::stripSensitiveData()); $sanitized_request = Terminus_Command::stripSensitiveData((string) $request, Terminus_Command::$_blacklist); \Terminus::error("Request %s had failed: %s", array($sanitized_request, $e->getMessage())); } catch (Exception $e) { \Terminus::error("Unrecognised request failure: %s", $e->getMessage()); } }
public function invalid_positionals($args) { $positionals = $this->query_spec(array('type' => 'positional')); for ($i = 0; $i < count($args); $i++) { if (!isset($positionals[$i]['token'])) { continue; } $token = preg_replace('#\\[?\\<([a-zA-Z].*)\\>\\]?.*#s', '$1', $positionals[$i]['token']); if ("commands" == trim($token) || "email" == trim($token)) { // we exit here because the wp and drush commands need to not have validation running since their commands are dependent on their respective code bases. return false; } $regex = "#^({$token})\$#s"; if (\Terminus::get_config('debug')) { Logger::coloredOutput("<Y>Positional match {$regex}</Y>"); } if (!preg_match($regex, $args[$i])) { return $args[$i]; } } return false; }
/** * Outputs basic workflow success/failure messages * * @param [Workflow] $workflow Workflow to output message about * @return [void] */ protected function workflowOutput($workflow) { if ($workflow->get('result') == 'succeeded') { Logger::coloredOutput('%2<K>' . $workflow->get('active_description') . '</K>'); } else { $final_task = $workflow->get('final_task'); Logger::redline($final_task->reason); } }
/** * Create a new site * * ## OPTIONS * * [--product=<productid>] * : Specify the product to create * * [--name=<name>] * : (deprecated) use --site instead * * [--site=<site>] * : Name of the site to create (machine-readable) * * [--label=<label>] * : Label for the site * * [--org=<org>] * : UUID of organization to add this site to; or "None" * * [--import=<url>] * : A url to import a valid archive from */ public function create($args, $assoc_args) { $sites = SiteFactory::instance(); // setup data $data = array(); $data['label'] = Input::string($assoc_args, 'label', "Human readable label for the site"); $slug = Utils\sanitize_name($data['label']); // this ugly logic is temporarily if to handle the deprecated --name flag and preserve backward compatibility. it can be removed in the next major release. if (array_key_exists('name', $assoc_args)) { $data['site_name'] = $assoc_args['name']; } elseif (array_key_exists('site', $assoc_args)) { $data['site_name'] = $assoc_args['site']; } else { $data['site_name'] = Input::string($assoc_args, 'site', "Machine name of the site; used as part of the default URL [ if left blank will be {$slug}]", $slug); } if ($orgid = Input::orgid($assoc_args, 'org', false)) { $data['organization_id'] = $orgid; } if (!isset($assoc_args['import'])) { $product = Input::product($assoc_args, 'product'); $data['deploy_product'] = array('product_id' => $product['id']); Terminus::line(sprintf("Creating new %s installation ... ", $product['longname'])); } $params = array('body' => json_encode($data), 'headers' => array('Content-type' => 'application/json')); // run the workflow $workflow = Workflow::createWorkflow('create_site', 'users', new User()); $workflow->setMethod('POST'); $workflow->setParams($data); $workflow->start(); $workflow->refresh(); $details = $workflow->status(); $site_id = $details->final_task->site_id; if ($details->result !== 'failed' and $details->result !== 'aborted') { Terminus\Loggers\Regular::coloredOutput('%G' . vsprintf('New "site" %s now building with "UUID" %s', array($data['site_name'], $site_id))); } $workflow->wait(); Terminus::success("Pow! You created a new site!"); $this->cache->flush(null, 'session'); if (isset($assoc_args['import'])) { Terminus::launch_self('site', array('import'), array('url' => $assoc_args['import'], 'site' => $data['site_name'], 'element' => 'all', 'nocache' => True)); } return true; }
/** * Print and save drush aliases * * ## OPTIONS * * [--print] * : print aliases to screen * * [--location=<location>] * : specify the location of the alias file, default it ~/.drush/pantheon.drushrc.php * */ public function aliases($args, $assoc_args) { $user = new User(); $print = Input::optional('print', $assoc_args, false); $json = \Terminus::get_config('json'); $location = Input::optional('location', $assoc_args, getenv("HOME") . '/.drush/pantheon.aliases.drushrc.php'); $message = "Pantheon aliases updated."; if (!file_exists($location)) { $message = "Pantheon aliases created."; } $content = $user->getAliases(); $h = fopen($location, 'w+'); fwrite($h, $content); fclose($h); chmod($location, 0777); Logger::coloredOutput("%2%K{$message}%n"); if ($json) { include $location; print \Terminus\Utils\json_dump($aliases); } elseif ($print) { print $content; } }
/** * Pings a site to ensure it responds * * ## OPTIONS * * [--site=<site>] * : site to ping * * [--env=<env>] * : environment to ping * * ## Examples * terminus site wake --site='testsite' --env=dev */ public function wake($args, $assoc_args) { $site = SiteFactory::instance(Input::site($assoc_args)); $env = Input::env($assoc_args, 'env'); $data = $site->environment($env)->wake(); if (!$data['success']) { Logger::redLine(sprintf("Could not reach %s", $data['target'])); return; } if (!$data['styx']) { Logger::redLine("Pantheon headers missing, which isn't quite right."); return; } Logger::greenLine(sprintf("OK >> %s responded in %s", $data['target'], $data['time'])); }
/** * Processes exception message and throws it * * @param [Exception] $exception Exception object thrown * @return [void] */ function handle_exception($exception) { $trace = $exception->getTrace(); if (!empty($trace) and \Terminus::get_config('verbose')) { foreach ($exception->getTrace() as $line) { $out_line = sprintf("%s%s%s [%s:%s]", $line['class'], $line['type'], $line['function'], $line['file'], $line['line']); \Terminus\Loggers\Regular::redLine(">> {$out_line}"); } } \Terminus::error("Exception thrown - %s", array($exception->getMessage())); }
/** * Print and save drush aliases * * ## OPTIONS * * [--print] * : print aliases to screen * * [--location=<location>] * : Specify the the full path, including the filename, to the alias file you wish to create. * Without this option a default of '~/.drush/pantheon.drushrc.php' will be used. * */ public function aliases($args, $assoc_args) { $user = new User(new stdClass(), array()); $print = Input::optional('print', $assoc_args, false); $json = \Terminus::get_config('json'); $location = Input::optional('location', $assoc_args, getenv("HOME") . '/.drush/pantheon.aliases.drushrc.php'); // Cannot provide just a directory if (is_dir($location)) { \Terminus::error("Please provide a full path with filename, e.g. %s/pantheon.aliases.drushrc.php", $location); exit(1); } $file_exists = file_exists($location); // Create the directory if it doesn't yet exist $dirname = dirname($location); if (!is_dir($dirname)) { mkdir($dirname, 0700, true); } $content = $user->getAliases(); $h = fopen($location, 'w+'); fwrite($h, $content); fclose($h); chmod($location, 0700); $message = $file_exists ? 'Pantheon aliases updated' : 'Pantheon aliases created'; Logger::coloredOutput("%2%K{$message}%n"); if ($json) { include $location; print \Terminus\Utils\json_dump($aliases); } elseif ($print) { print $content; } }
/** * Pings a site to ensure it responds * * ## OPTIONS * * [--site=<site>] * : site to ping * * [--env=<env>] * : environment to ping * * ## Examples * terminus site wake --site='testsite' --env=dev */ public function wake($args, $assoc_args) { $site = $this->sites->get(Input::sitename($assoc_args)); $env = Input::env($assoc_args, 'env'); $data = $site->environments->get($env)->wake(); if (!$data['success']) { Logger::redLine(sprintf('Could not reach %s', $data['target'])); return; } if (!$data['styx']) { Terminus::error('Pantheon headers missing, which is not quite right.'); } Terminus::success(sprintf('OK >> %s responded in %s', $data['target'], $data['time'])); }