protected function send_command($server, $remote_exec, $args, $assoc_args) { # unset CLI args unset($assoc_args['site']); $remote_cmd = $remote_exec . ' '; foreach ($args as $arg) { $remote_cmd .= escapeshellarg($arg) . ' '; } foreach ($assoc_args as $key => $value) { if ($value != 1) { $remote_cmd .= ' --' . $key . '=' . escapeshellarg($value); } else { $remote_cmd .= ' --' . $key; } } $cmd = 'ssh -T ' . $server['user'] . '@' . $server['host'] . ' -p ' . $server['port'] . ' -o "AddressFamily inet"' . " " . escapeshellarg($remote_cmd); if (\Terminus::get_config('silent')) { ob_start(); } passthru($cmd, $exit_code); if (\Terminus::get_config('silent')) { $this->logger->info(ob_get_clean()); } if ($exit_code == 255) { $this->logger->error("Failed to connect. Check your credentials, and that you are specifying a valid environment."); } return $exit_code; }
/** * Make a request to the Pantheon API * * @param [string] $realm Permissions realm for data request (e.g. user, * site organization, etc. Can also be "public" to simply pull read-only * data that is not privileged. * @param [string] $uuid The UUID of the item in the realm to access * @param [string] $path API path (URL) * @param [string] $method HTTP method to use * @param [mixed] $options A native PHP data structure (e.g. int, string, * array, or stdClass) to be sent along with the request * @return [array] $data */ 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(); $sanitized_request = TerminusCommand::stripSensitiveData((string) $request, TerminusCommand::$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; }
public static function send($url, $method, $data = array()) { // create a new Guzzle\Http\Client $browser = new Browser(); $browser->setUserAgent(self::userAgent()); $options = array('allow_redirects' => false, 'verify' => false, 'json' => false); if (isset($data['allow_redirects'])) { $options['allow_redirects'] = $data['allow_redirects']; } if (isset($data['json'])) { $options['json'] = $data['json']; } if (isset($data['body']) && $data['body']) { $options['body'] = $data['body']; if (\Terminus::get_config('debug')) { \Terminus::log('debug', $data['body']); } } $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::log('debug', $debug); if (isset($data['body'])) { \Terminus::log('debug', $data['body']); } } $response = $request->send(); return $response; }
function get_longdesc() { $binding = array(); foreach (\Terminus::get_configurator()->get_spec() as $key => $details) { if ($details['runtime'] === false || isset($details['deprecated']) || isset($details['hidden'])) { continue; } if ($details['runtime']) { $synopsis = "--[no-]{$key}"; } else { $synopsis = "--{$key}" . $details['runtime']; } $binding['parameters'][] = array('synopsis' => $synopsis, 'desc' => $details['desc']); } if ((bool) \Terminus::get_config('json')) { return $binding; } return Utils\mustache_render('man-params.mustache', $binding); }
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; }
/** * 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())); }
/** * Ask for confirmation before running a destructive operation. */ static function confirm($question, $assoc_args = array(), $params = array()) { if (\Terminus::get_config('yes')) { return true; } $question = vsprintf($question, $params); fwrite(STDOUT, $question . " [y/n] "); $answer = trim(fgets(STDIN)); if ('y' != $answer) { exit; } return true; }
function invoke($args, $assoc_args, $extra_args) { if (\Terminus::get_config('interactive')) { list($args, $assoc_args) = $this->prompt_args($args, $assoc_args); } $to_unset = $this->validate_args($args, $assoc_args, $extra_args); foreach ($to_unset as $key) { unset($assoc_args[$key]); } $path = get_path($this->get_parent()); call_user_func($this->when_invoked, $args, array_merge($extra_args, $assoc_args)); }
protected function handleDisplay($data, $args = array(), $headers = null) { if (array_key_exists("json", $args) or Terminus::get_config('json')) { echo \Terminus\Utils\json_dump($data); } else { if (array_key_exists("bash", $args) or Terminus::get_config('bash')) { echo \Terminus\Utils\bash_out((array) $data); } else { $this->_constructTableForResponse((array) $data, $headers); } } }
/** * Waits and returns response from workflow * * @param [string] $object_name Sites/users/organizations/etc * @param [string] $object_id UUID of $object_name * @param [string] $workflow_id Workflow UUID to wait on * @return [array] $workflow['data'] Result of the request * * @deprecated Use new WorkFlow() object instead */ protected function waitOnWorkflow($object_name, $object_id, $workflow_id) { print "Working ."; $workflow = self::request($object_name, $object_id, "workflows/{$workflow_id}", 'GET'); $result = $workflow['data']->result; $desc = $workflow['data']->active_description; $type = $workflow['data']->type; $tries = 0; while (!isset($result)) { if (in_array($result, array('failed', 'aborted'))) { if (isset($workflow['data']->final_task) && !empty($workflow['data']->final_task->messages)) { foreach ($workflow['data']->final_task->messages as $message) { sprintf('[%s] %s', $message->level, $message->message); } } else { Terminus::error(PHP_EOL . "Couldn't complete workflows: '{$type}'" . PHP_EOL); } } $workflow = self::request($object_name, $object_id, "workflows/{$workflow_id}", 'GET'); $result = $workflow['data']->result; if (Terminus::get_config('debug')) { print_r($workflow); } sleep(3); print "."; $tries++; } print PHP_EOL; if (in_array($workflow['data']->result, array("succeeded", "aborted"))) { return $workflow['data']; } return false; }
/** * Hostname operations * * ## OPTIONS * * <list|add|remove> * : OPTIONS are list, add, delete * * [--site=<site>] * : Site to use * * --env=<env> * : environment to use * * [--hostname=<hostname>] * : hostname to add * */ public function hostnames($args, $assoc_args) { $action = array_shift($args); $site = $this->sites->get(Input::sitename($assoc_args)); $env = $site->environments->get(Input::env($assoc_args, 'env')); switch ($action) { case 'list': $hostnames = $env->getHostnames(); $data = $hostnames; if (!Terminus::get_config('json')) { //If were not just dumping the JSON, then we should reformat the data. $data = array(); foreach ($hostnames as $hostname => $details) { $data[] = array_merge(array('domain' => $hostname), (array) $details); } } $this->outputter->outputRecordList($data); break; case 'add': if (!isset($assoc_args['hostname'])) { Terminus::error('Must specify hostname with --hostname'); } $data = $env->addHostname($assoc_args['hostname']); if (Terminus::get_config('verbose')) { \Terminus\Utils\json_dump($data); } Terminus::success('Added %s to %s-%s', array($assoc_args['hostname'], $site->get('name'), $env->get('id'))); break; case 'remove': if (!isset($assoc_args['hostname'])) { Terminus::error('Must specify hostname with --hostname'); } $data = $env->deleteHostname($assoc_args['hostname']); Terminus::success('Deleted %s from %s-%s', array($assoc_args['hostname'], $site->get('name'), $env->get('id'))); break; } return $data; }
/** * Hostname operations * * ## OPTIONS * * <list|add|remove> * : OPTIONS are list, add, delete * * [--site=<site>] * : Site to use * * --env=<env> * : environment to use * * [--hostname=<hostname>] * : hostname to add * */ public function hostnames($args, $assoc_args) { $action = array_shift($args); $site = $this->sites->get(Input::sitename($assoc_args)); $env = $site->environments->get(Input::env($assoc_args, 'env')); switch ($action) { case 'list': $hostnames = $env->getHostnames(); $data = $hostnames; if (!Terminus::get_config('json')) { //If were not just dumping the JSON, then we should reformat the data. $data = array(); foreach ($hostnames as $hostname => $details) { $data[] = array_merge(array('domain' => $hostname), (array) $details); } } $this->output()->outputRecordList($data); break; case 'add': if (!isset($assoc_args['hostname'])) { throw new TerminusException('Must specify hostname with --hostname'); } $data = $env->addHostname($assoc_args['hostname']); if (Terminus::get_config('verbose')) { Utils\json_dump($data); } $this->log()->info('Added {hostname} to {site}-{env}', array('hostname' => $assoc_args['hostname'], 'site' => $site->get('name'), 'env' => $env->get('id'))); break; case 'remove': if (!isset($assoc_args['hostname'])) { throw new TerminusException('Must specify hostname with --hostname'); } $data = $env->deleteHostname($assoc_args['hostname']); $this->log()->info('Deleted {hostname} from {site}-{env}', array('hostname' => $assoc_args['hostname'], 'site' => $site->get('name'), 'env' => $env->get('id'))); break; } return $data; }
/** * Same as confirm but doesn't exit * * @param [string] $question Question to ask * @param [array] $params Args for vsprintf() * * @return [boolean] $is_yes */ public static function yesno($question, $params = array()) { if (\Terminus::get_config('yes')) { return true; } $question = vsprintf($question, $params); fwrite(STDOUT, $question . " [y/n] "); $answer = trim(fgets(STDIN)); $is_yes = (bool) ($answer == 'y'); return $is_yes; }
/** * Lock an environment to prevent changes * * ## OPTIONS * * <info|add|remove> * : action to execute ( i.e. info, add, remove ) * * [--site=<site>] * : site name * * [--env=<env>] * : site environment * * [--username=<username>] * : your username * * [--password=<password>] * : your password * **/ function lock($args, $assoc_args) { $action = array_shift($args); $site = SiteFactory::instance(Input::site($assoc_args)); $env = Input::env($assoc_args, 'env'); switch ($action) { case 'info': $data = $locks = $site->environment($env)->lockinfo(); if (!Terminus::get_config('json')) { $data = array($data); } $this->handleDisplay($data); break; case 'add': Terminus::line("Creating new lock on %s -> %s", array($site->getName(), $env)); if (!isset($assoc_args['username'])) { $email = Terminus::prompt("Username for the lock"); } else { $email = $assoc_args['username']; } if (!isset($assoc_args['password'])) { exec("stty -echo"); $password = Terminus::prompt("Password for the lock"); exec("stty echo"); Terminus::line(); } else { $password = $assoc_args['password']; } $data = $site->environment($env)->lock($email, $password); if ($data and property_exists($data, 'id')) { $this->waitOnWorkflow('sites', $data->site_id, $data->id); } Terminus::success('Success'); break; case 'remove': Terminus::line("Removing lock from %s -> %s", array($site->getName(), $env)); $data = $site->environment($env)->unlock(); if (property_exists($data, 'id')) { $this->waitOnWorkflow('sites', $data->site_id, $data->id); } Terminus::success('Success'); } }
/** * 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; } }
/** * 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; } }
private static function render_subcommands($command) { $subcommands = array(); foreach ($command->get_subcommands() as $subcommand) { $subcommands[$subcommand->get_name()] = $subcommand->get_shortdesc(); } if ((bool) Terminus::get_config('json')) { return $subcommands; } $max_len = self::get_max_len(array_keys($subcommands)); $lines = array(); foreach ($subcommands as $name => $desc) { $lines[] = str_pad($name, $max_len) . "\t\t\t" . $desc; } return $lines; }
/** * Hostname operations * * ## OPTIONS * * <list|add|remove> * : OPTIONS are list, add, delete * * [--site=<site>] * : Site to use * * --env=<env> * : environment to use * * [--hostname=<hostname>] * : hostname to add * */ public function hostnames($args, $assoc_args) { $action = array_shift($args); $site = SiteFactory::instance(Input::sitename($assoc_args)); $env = Input::env($assoc_args, 'env'); switch ($action) { case 'list': $hostnames = $data = (array) $site->environment($env)->hostnames(); if (!Terminus::get_config('json')) { // if were not just dumping the json then we should reformat the data $data = array(); foreach ($hostnames as $hostname => $details) { $data[] = array_merge(array('domain' => $hostname), (array) $details); } } $this->handleDisplay($data); break; case 'add': if (!isset($assoc_args['hostname'])) { Terminus::error("Must specify hostname with --hostname"); } $data = $site->environment($env)->hostnameadd($assoc_args['hostname']); if (Terminus::get_config('verbose')) { \Terminus\Utils\json_dump($data); } Terminus::success("Added %s to %s-%s", array($assoc_args['hostname'], $site->getName(), $env)); break; case 'remove': if (!isset($assoc_args['hostname'])) { Terminus::error("Must specify hostname with --hostname"); } $data = $site->environment($env)->hostnamedelete($assoc_args['hostname']); Terminus::success("Deleted %s from %s-%s", array($assoc_args['hostname'], $site->getName(), $env)); break; } return $data; }
/** * Delete a site from pantheon * * ## OPTIONS * [--site=<site>] * : ID of the site you want to delete * * [--force] * : to skip the confirmations */ function delete($args, $assoc_args) { $sitename = Input::sitename($assoc_args); $site_id = $this->sitesCache->findID($sitename); $site_to_delete = new Site($site_id); if (!isset($assoc_args['force']) and !Terminus::get_config('yes')) { // if the force option isn't used we'll ask you some annoying questions Terminus::confirm(sprintf("Are you sure you want to delete %s?", $site_to_delete->information->name)); Terminus::confirm("Are you really sure?"); } Terminus::line(sprintf("Deleting %s ...", $site_to_delete->information->name)); $response = \Terminus_Command::request('sites', $site_to_delete->id, '', 'DELETE'); $this->sitesCache->remove($sitename); Terminus::success("Deleted %s!", $sitename); }